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
Complete Multi-Tenant SaaS Guide: NestJS, Prisma & PostgreSQL with Database-per-Tenant Architecture

Learn to build scalable multi-tenant SaaS apps with NestJS, Prisma & PostgreSQL. Master database isolation, dynamic connections & tenant security. Complete guide with code examples.

Blog Image
Build Full-Stack Apps Fast with Vue.js and Pocketbase

Discover how Vue.js and Pocketbase simplify full-stack app development with real-time features, built-in auth, and zero backend setup.

Blog Image
Build High-Performance GraphQL APIs with NestJS, Prisma, and Redis Caching for Scalable Applications

Learn to build a scalable GraphQL API using NestJS, Prisma ORM, and Redis caching. Master DataLoader patterns, authentication, and performance optimization techniques.

Blog Image
How to Integrate Prisma with GraphQL: Complete Type-Safe Backend Development Guide 2024

Learn how to integrate Prisma with GraphQL for type-safe database operations and powerful API development. Build robust backends with seamless data layer integration.

Blog Image
Complete Guide to Integrating Next.js with Prisma ORM for Type-Safe Database Operations in 2024

Learn how to integrate Next.js with Prisma ORM for type-safe database operations. Build scalable web apps with seamless data management and improved developer experience.

Blog Image
Build Type-Safe Event-Driven Architecture with TypeScript, Redis Streams, and NestJS

Learn to build scalable event-driven architecture with TypeScript, Redis Streams & NestJS. Create type-safe handlers, reliable event processing & microservices communication. Get started now!