DEV Community

Alex Spinov
Alex Spinov

Posted on

Encore.ts Has a Free API: Build Type-Safe Backend Services With Zero Boilerplate

Encore.ts is a backend framework that generates infrastructure from your TypeScript code. Define an API endpoint, and Encore automatically creates cloud infrastructure — databases, pub/sub, cron jobs, and more.

Why Encore?

  • Zero boilerplate — define API, get infrastructure automatically
  • Type-safe — end-to-end types from API to client
  • Auto-infrastructure — databases, queues, cron from code annotations
  • Local dev dashboard — traces, API explorer, architecture diagram
  • Free cloud — deploy to Encore Cloud or self-host

Quick Start

npm install -g encore.dev
encore app create my-app --lang=ts
cd my-app
encore run  # Dev server with dashboard at http://localhost:9400
Enter fullscreen mode Exit fullscreen mode

Define APIs

// backend/user/user.ts
import { api } from 'encore.dev/api';
import { SQLDatabase } from 'encore.dev/storage/sqldb';

// Database defined in code — Encore creates it!
const db = new SQLDatabase('users', {
  migrations: './migrations',
});

interface User {
  id: number;
  name: string;
  email: string;
}

interface CreateUserParams {
  name: string;
  email: string;
}

// POST /user — Encore infers method from function name + params
export const create = api(
  { expose: true, method: 'POST', path: '/user' },
  async (params: CreateUserParams): Promise<User> => {
    const row = await db.queryRow<User>`
      INSERT INTO users (name, email) VALUES (${params.name}, ${params.email})
      RETURNING id, name, email
    `;
    return row!;
  }
);

// GET /user/:id
export const get = api(
  { expose: true, method: 'GET', path: '/user/:id' },
  async ({ id }: { id: number }): Promise<User> => {
    const row = await db.queryRow<User>`
      SELECT id, name, email FROM users WHERE id = ${id}
    `;
    if (!row) throw new Error('User not found');
    return row;
  }
);

// GET /users
export const list = api(
  { expose: true, method: 'GET', path: '/users' },
  async (): Promise<{ users: User[] }> => {
    const rows = await db.query<User>`SELECT id, name, email FROM users`;
    return { users: rows };
  }
);
Enter fullscreen mode Exit fullscreen mode

Pub/Sub (Defined in Code)

import { Topic, Subscription } from 'encore.dev/pubsub';

interface UserCreatedEvent {
  userId: number;
  email: string;
}

// Topic — Encore creates the infrastructure!
export const userCreated = new Topic<UserCreatedEvent>('user-created', {
  deliveryGuarantee: 'at-least-once',
});

// Publish
await userCreated.publish({ userId: 1, email: 'alice@example.com' });

// Subscribe — auto-creates subscription
const _ = new Subscription(userCreated, 'send-welcome-email', {
  handler: async (event) => {
    await sendEmail(event.email, 'Welcome!');
  },
});
Enter fullscreen mode Exit fullscreen mode

Cron Jobs

import { CronJob } from 'encore.dev/cron';

const _ = new CronJob('daily-cleanup', {
  title: 'Clean up expired sessions',
  schedule: '0 2 * * *', // 2 AM daily
  endpoint: cleanup,
});

export const cleanup = api(
  { expose: false },
  async () => {
    await db.exec`DELETE FROM sessions WHERE expires_at < NOW()`;
  }
);
Enter fullscreen mode Exit fullscreen mode

Key Features

Feature Details
Language TypeScript (Go also supported)
APIs Auto-generated from code
Database SQL from code annotations
Pub/Sub From code, auto-provisioned
Cron Defined in code
Dashboard Local dev traces, API explorer
Deploy Encore Cloud or self-host

Resources


Building backend services? Check my Apify actors or email spinov001@gmail.com.

Top comments (0)