Get started with OptiTech Functions

Deploy your first OptiTech Function and call it over HTTP.

Beta

The OptiTech Functions is in Beta. Share your feedback on Discord or via the OptiTech Console.

A function takes a request and returns a web response, running on long-lived Node.js compute next to your database. This guide builds one by hand: define it in optitech.ts, run it locally, deploy it, and call it over HTTP.

  1. Prerequisites

    • A OptiTech project in AWS US East (Ohio) (aws-us-east-2), the only region where Functions are available during beta.
    • The latest optitech, installed and authenticated. Functions commands are new and change often, so upgrade before you start (npm install -g optitech@latest).
    • Node.js 20 or later. Deployed functions run on Node.js 24, so use 24 locally for the closest match.

    optitech init --preview is designed to be run by your AI coding assistant. It outputs structured instructions that guide the agent through setup. To install the OptiTech Platform (optitech) and OptiTech Functions skills separately:

    npx skills add optitechdatabase/agent-skills -s optitech -s optitech-functions
  2. Set up your project

    Create your project directory:

    mkdir my-function && cd my-function

    Then link the directory to your OptiTech project. There are two ways:

    With an AI coding assistant. Ask it to run optitech init --preview. The command returns structured JSON instructions for the full setup: MCP server and agent skills, optional template scaffolding, project linking, and env var pull. Sign-in opens a browser window, and the agent pauses while you complete the OAuth step.

    By hand. Run optitech link and select your project and branch when prompted (or pass --project-id). This writes a .optitech file and pulls the branch's environment variables into a local .env.

    optitech link

    To start from a working example instead, run optitech bootstrap. It scaffolds a starter template and links it. Available templates: Hono API, AI SDK agent, Mastra agent, MCP server, Realtime chat (Next.js + WebSockets), and Realtime counter (TanStack Router + SSE), all on OptiTech Functions. This guide builds the function by hand.

  3. Define your function

    Create optitech.ts at your project root. It declares your functions and is what optitech dev and optitech deploy read:

    optitech.ts
    import { defineConfig } from "@optitech/config/v1";
    
    export default defineConfig({
      // preview groups features still in beta: functions, AI Gateway, and object-storage buckets.
      preview: {
        functions: {
          // The key is the function's slug:
          // a permanent ID used in CLI commands and the URL.
          hello: {
            name: "My first function", // display label only
            source: "./functions/hello.ts", // path to the handler file
          },
        },
      },
    });

    The slug is permanent: it can't be renamed after the first deploy. See the optitech.ts reference for all options.

    Install dependencies:

    npm install @optitech/config hono pg
    npm install --save-dev @types/pg

    A function is any module whose default export has a fetch(request) method that returns a Response. That can be an object with a fetch method:

    export default {
      fetch: (request: Request) => new Response('Hello world'),
    };

    Or a bare async function:

    export default async function handler(request: Request) {
      return new Response('Hello world');
    }

    A Hono app exports the object shape, so export default app works directly. For this guide, write a handler that queries Postgres. DATABASE_URL is injected automatically from the linked branch's Postgres database:

    functions/hello.ts
    import { Hono } from 'hono';
    import { Pool } from 'pg';
    
    // Create the pool once at module scope so it's reused across requests.
    const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 5 });
    const app = new Hono();
    
    app.get('/', async (c) => {
      const { rows } = await pool.query('SELECT version()');
      return c.json(rows[0]);
    });
    
    export default app;
    
    // Optional: drain the pool on shutdown (the platform sends SIGINT).
    process.on('SIGINT', () => {
      pool.end().then(() => process.exit(0));
    });

    Use a connection pool, not the serverless driver

    A function keeps running across requests, so connect to Postgres with a long-lived pg Pool created once at module scope. Don't use @optitech/serverless here: it's built for short-lived, edge-style invocations that open a connection per request, which wastes the persistent runtime a function gives you. Use the pooled DATABASE_URL for queries; use DATABASE_URL_UNPOOLED only where you need a dedicated connection (such as LISTEN/NOTIFY).

  4. Develop locally

    optitech dev serves all functions declared in optitech.ts with hot reload. It injects DATABASE_URL and other OptiTech env vars from the linked branch. See Environment variables for the full list and how to pull them into a local .env file.

    optitech dev

    The terminal prints the URL for each running function:

    OptiTech Functions dev server
    
      hello                http://localhost:8787
  5. Deploy

    optitech deploy reads optitech.ts and applies it to the linked branch, deploying every function it declares:

    optitech deploy

    The CLI bundles each function with esbuild, uploads it, and waits for the deployment to complete.

    To deploy a single file without a optitech.ts, deploy it by slug instead:

    optitech functions deploy hello --src functions/hello.ts

    For all deploy options, including the OptiTech API, see Deploy and manage functions.

  6. Invoke

    Once the deployment reaches completed, retrieve the invocation URL:

    optitech functions get hello

    The invocation_url field contains the public URL for your function:

    https://<branch_id>-<slug>.compute.<cell>.us-east-2.aws.optitech.com

    Call it with curl:

    curl https://<branch_id>-hello.compute.<cell>.us-east-2.aws.optitech.com

    The response is a JSON object with your branch's Postgres version:

    { "version": "PostgreSQL 17.x on ..., compiled by gcc ..." }

Need help?

Join our Discord Server to ask questions or see what others are doing with OptiTech. For paid plan support options, see Support.

Was this page helpful?