js

Build Lightning-Fast APIs with Bun, Elysia, and PostgreSQL

Discover a modern backend stack using Bun, Elysia, and PostgreSQL for blazing-fast, type-safe, and scalable API development.

Build Lightning-Fast APIs with Bun, Elysia, and PostgreSQL

I’ve been thinking about how we build web services lately. It feels like we’re at a turning point. For years, Node.js and Express have been the default choice, but something new is happening. The tools are getting faster, simpler, and more focused. I want to show you a different way to build APIs that might just change how you think about backend development.

Have you ever waited for a serverless function to start up? That delay is real. What if you could make it almost disappear?

Let’s talk about Bun. It’s not just another JavaScript runtime. It’s built from the ground up to be fast. Really fast. When I first tried it, the startup time caught me off guard. My API was ready before I could blink. For serverless environments, where cold starts can ruin user experience, this matters.

Then there’s Elysia. It’s a web framework designed for Bun. It feels light, almost effortless. You write your routes, and it just works. The type safety is something special. Your editor knows what you’re trying to do before you finish typing.

But an API needs data. That’s where PostgreSQL comes in. It’s reliable, powerful, and when paired correctly, incredibly fast. The secret? Connection pooling. Instead of opening a new database connection for every request, you keep a pool ready. It’s like having a team of database workers waiting for instructions.

Why does this combination work so well? Each piece solves a specific problem. Bun handles the execution speed. Elysia manages the request flow with elegance. PostgreSQL stores the data securely. The connection pool makes sure they talk to each other efficiently.

Here’s how you start. First, install Bun. It’s a single command.

curl -fsSL https://bun.sh/install | bash

Create a new project directory and initialize it.

mkdir my-api && cd my-api
bun init -y

Now add the essential packages. Notice how few dependencies we need.

bun add elysia
bun add pg pg-pool

Let’s set up our database connection. This is where the pooling happens. Create a file called database.ts.

import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  max: 10,
  min: 2,
  idleTimeoutMillis: 30000
});

export const db = {
  query: (text: string, params?: any[]) => pool.query(text, params)
};

Simple, right? We create a pool with minimum and maximum connections. The pool manages everything for us. When a request comes in, it grabs an available connection. When the request finishes, the connection goes back to the pool.

Now let’s build our API with Elysia. Create an index.ts file.

import { Elysia } from 'elysia';
import { db } from './database';

const app = new Elysia()

app.get('/users', async () => {
  const result = await db.query('SELECT * FROM users LIMIT 100');
  return result.rows;
})

app.get('/users/:id', async ({ params }) => {
  const result = await db.query('SELECT * FROM users WHERE id = $1', [params.id]);
  return result.rows[0] || null;
})

app.post('/users', async ({ body }) => {
  const { name, email } = body as any;
  const result = await db.query(
    'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
    [name, email]
  );
  return result.rows[0];
})

app.listen(3000);
console.log('Server running on http://localhost:3000');

Look at how clean that is. Each route is a simple function. The database calls are straightforward. But we can do better. What about validation? What about error handling?

Elysia has a beautiful way to handle schemas. Let me show you.

import { Elysia, t } from 'elysia';

const app = new Elysia()

app.post('/users', async ({ body }) => {
  // body is automatically validated
  const result = await db.query(
    'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
    [body.name, body.email]
  );
  return result.rows[0];
}, {
  body: t.Object({
    name: t.String({ minLength: 2 }),
    email: t.String({ format: 'email' })
  })
})

The validation happens before your function even runs. If the data doesn’t match the schema, Elysia returns an error automatically. Your function only receives valid data.

But what happens when something goes wrong? The database might be down. A query might fail. We need to handle these cases.

app.onError(({ code, error }) => {
  console.error('Error:', error);
  
  if (code === 'VALIDATION') {
    return { error: 'Invalid data provided' };
  }
  
  return { error: 'Something went wrong' };
});

This catches errors across your entire application. You can customize the response based on the error type. Users get helpful messages instead of technical details.

Now, let’s think about production. In a serverless environment, your function might be shut down between requests. We need to handle database connections carefully.

let pool: Pool | null = null;

export const getDb = () => {
  if (!pool) {
    pool = new Pool({
      connectionString: process.env.DATABASE_URL,
      max: 1, // Single connection for serverless
      idleTimeoutMillis: 30000
    });
  }
  return pool;
};

Notice the max: 1 setting. In serverless, each function instance gets its own connection. This prevents connection limits from being exceeded. When the function stops, the connection closes automatically.

What about testing? Bun comes with a test runner built in.

import { describe, expect, test } from 'bun:test';
import { app } from './index';

describe('Users API', () => {
  test('GET /users returns array', async () => {
    const response = await app.handle(
      new Request('http://localhost/users')
    );
    const data = await response.json();
    expect(Array.isArray(data)).toBe(true);
  });
});

You can run tests with bun test. It’s fast. Really fast. The same speed benefits apply to your test suite.

Deployment is straightforward too. Most platforms support Bun now. Here’s a basic Dockerfile:

FROM oven/bun:latest

WORKDIR /app
COPY package.json .
COPY bun.lockb .

RUN bun install --production

COPY . .

CMD ["bun", "run", "src/index.ts"]

Build it, push it, and you’re done. The image is small because Bun includes everything you need.

But is this actually better than the traditional approach? Let’s compare. With Node.js and Express, you might use several middleware packages. Each adds overhead. With Bun and Elysia, you get more with less. The performance difference is noticeable, especially in serverless environments.

The real question is: what are you building? If it’s a simple API that needs to scale, this stack works beautifully. If you need real-time features or complex websocket handling, you might need additional tools. But for most REST APIs, it’s more than enough.

I’ve built several production services with this combination. The developer experience is excellent. The performance is outstanding. The simplicity is refreshing. You spend less time configuring and more time building.

Remember that connection pool we set up? It’s doing important work behind the scenes. Managing connections efficiently. Preventing timeouts. Handling errors gracefully. All while you focus on your business logic.

What surprised me most was how little code I needed. The frameworks get out of the way. The database interactions feel natural. The whole system feels cohesive, like each part was designed to work with the others.

Try it for your next project. Start small. Build a single endpoint. See how it feels. The setup is quick, and the results might surprise you.

I’d love to hear what you build with this approach. Share your experiences in the comments below. If you found this helpful, please pass it along to someone who might benefit from it. Let’s build better APIs, together.


As a best-selling author, I invite you to explore my books on Amazon. Don’t forget to follow me on Medium and show your support. Thank you! Your support means the world!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!


📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!


Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Keywords: bun,elysia,postgresql,api development,serverless



Similar Posts
Blog Image
Build Type-Safe Event-Driven Architecture with TypeScript, NestJS, and Redis Streams: Complete Guide

Learn to build type-safe event-driven architecture with TypeScript, NestJS & Redis Streams. Master event sourcing, microservices communication & production deployment strategies.

Blog Image
How to Prevent CSRF Attacks in Express.js Using JWT and Secure Tokens

Learn how to protect your Express.js apps from CSRF attacks using JWT, Double-Submit Cookies, and Synchronizer Tokens.

Blog Image
Event-Driven Microservices: Complete NestJS, RabbitMQ, MongoDB Guide with Real-World Examples

Learn to build scalable event-driven microservices with NestJS, RabbitMQ & MongoDB. Master async communication, CQRS patterns & error handling for distributed systems.

Blog Image
Next.js Prisma Integration Guide: Build Type-Safe Full-Stack Apps with Modern Database ORM

Learn how to integrate Next.js with Prisma ORM for type-safe, database-driven web apps. Build faster with seamless full-stack development and modern tooling.

Blog Image
How to Integrate Next.js with Prisma: Complete TypeScript Full-Stack Development Guide 2024

Learn how to integrate Next.js with Prisma for type-safe full-stack TypeScript apps. Build seamless database connections with auto-generated types and optimized queries.

Blog Image
Complete Guide to Next.js Prisma Integration: Build Type-Safe Full-Stack Apps in 2024

Learn how to integrate Next.js with Prisma ORM for type-safe, full-stack web applications. Build database-driven apps with seamless data flow and TypeScript support.