# Coding agents Source: https://docs.specific.dev/coding-agents Give your coding agent everything it needs to build and deploy with Specific. Specific is designed to be operated by coding agents. Your agent writes the code *and* defines the infrastructure to run it, with the same `specific.hcl` and the same CLI. This page covers how to connect an agent and how agents consume Specific's documentation. ## Connect your agent Inside your project, run: ```bash theme={null} specific init ``` This writes Specific usage instructions into the right place for your agent, auto-detected from your project (or pass `--agent` explicitly): | Agent | What's written | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | Claude Code (`claude`) | Instructions appended to `CLAUDE.md`, plus permissions for `specific docs` and `specific check` in `.claude/settings.local.json`. | | Codex (`codex`) | Instructions appended to `AGENTS.md`. | | Cursor (`cursor`) | A rule file at `.cursor/rules/specific.mdc`. | | Other (`other`) | Instructions appended to `AGENTS.md`. | ```bash theme={null} specific init --agent claude cursor ``` It also adds `.specific` and `specific.local` to `.gitignore`. From then on, the agent knows to define infrastructure in `specific.hcl`, validate with `specific check`, run everything with `specific dev`, and consult `specific docs` when it needs details. ## Docs built into the CLI The CLI ships its own LLM-optimized documentation, so agents never depend on stale training data or web access: ```bash theme={null} specific docs # the documentation index specific docs services # a specific topic specific docs integrations/nextjs # framework-specific guidance specific docs migrations/supabase # migrating from other platforms ``` The docs are nested and cross-linked; agents navigate them by path. They ship with the CLI binary, so they always match the installed version. ## Agent skill For agents that support skills, a Specific skill is available at [docs.specific.dev/skill.md](https://docs.specific.dev/skill.md). It contains the product summary, install command, and essential commands: enough for an agent to bootstrap itself, install the CLI, and pull deeper documentation via `specific docs`. ## This documentation site Every page on docs.specific.dev is also available to agents and LLM tools: * [`/llms.txt`](https://docs.specific.dev/llms.txt) - an index of all pages for LLM consumption, and [`/llms-full.txt`](https://docs.specific.dev/llms-full.txt) for the full content. * Append `.md` to any page URL for clean markdown. * The contextual menu on every page offers copy-as-markdown and open-in-ChatGPT/Claude shortcuts. ## Agents operating remotely Specific runs fully headless, so agents in remote environments like OpenClaw or Hermes can install the CLI, build, and deploy without a human at the machine. See the [OpenClaw setup instructions](/for-ai/openclaw) for a ready-to-use prompt that configures such an environment. Two pieces make this work: * **Tunnels**: an agent on a machine you can't browse from can still show you the running app. `specific dev --tunnel` exposes public services at `https://.tunnel.spcf.app`. * **Device-code login**: logging in without a browser works via the device-code flow. `specific deploy` and `specific login` print an authorization link and code, and `specific login --device-code ` completes it. ## What stays the human's job * Confirming the CLI installation. * DNS changes for [custom domains](/guides/domains) - the CLI prints the records, but you configure them at your registrar. * Production management in the [dashboard](https://dashboard.specific.dev): scaling, secrets rotation, domain removal, billing. # Specific vs Convex Source: https://docs.specific.dev/compare/convex Convex is a backend platform that replaces your database, server, and real-time layer with a single proprietary runtime. You write mutations, queries, and actions in Convex's format, and your data lives in Convex's document-oriented store. Specific takes a different approach: your coding agent defines standard infrastructure in a config file, and your code stays portable by building on open-source technology like PostgreSQL. | | Convex | Specific | | ---------------------- | ---------------------------------- | ------------------------------------------------ | | **Data model** | Proprietary document store | Standard PostgreSQL | | Query language | Convex query/mutation functions | Standard SQL through Postgres | | Backend logic | Convex actions (JS/TS only) | Any stack, standard backend code without lock-in | | Real-time | Reactive queries through SDK | Built-in sync engine that works with any stack | | Code portability | Tightly coupled to Convex runtime | Standard code with no vendor lock-in | | Storage | Convex file storage API | S3-compatible, any S3 client | | Open-source foundation | Proprietary data store and runtime | Standard protocols like PostgreSQL and S3 | | Agent integration | Not designed for agents | Agent-first | ## Designed for coding agents Convex targets human developers writing backend logic in its proprietary format: mutations, queries, and actions that follow Convex-specific conventions. This is a workflow optimized for humans reading Convex documentation. Specific is built so that coding agents define infrastructure, deploy services, and debug issues through a config file and CLI. This is the workflow agents are best at: writing configuration, running commands, and interpreting structured output. ## Built on open-source, not proprietary infrastructure Convex uses a proprietary document store and runtime that is not open-source. Your data lives in a system controlled by a single vendor, with no standard tooling ecosystem around it. Specific builds on battle-tested open-source technology: standard PostgreSQL for your data, S3-compatible storage, and Redis for caching. These are systems with decades of community support, tooling, and portability. If you ever need to move, your data and your knowledge transfer with you. ## No vendor-specific code in your application With Convex, your backend logic is written as Convex mutations, queries, and actions, a format that only runs on the Convex runtime. Your application code is tightly coupled to one platform. With Specific, you write a normal code using any programming language and stack, whatever fits your project. Your code is standard and portable. If you switch infrastructure providers, your application code still works. ## Any language, not just TypeScript Convex backend functions must be written in JavaScript or TypeScript. If your project needs a different language Convex can't accommodate that. Specific supports any language or framework. Your services can run Node.js, Python, Go, Rust, or anything else. Pick the right tool for the job. Clone an example project and get familiar with Specific Install Specific for your own project and get started building # Specific vs Supabase Source: https://docs.specific.dev/compare/supabase Supabase is a popular backend-as-a-service that bundles Postgres, auth, real-time subscriptions, and storage behind a client-side SDK. This means you need to lock your code into their SDK. Specific takes a different approach: instead of routing everything through an SDK, your coding agent defines the infrastructure it needs in a configuration file, and your code uses standard tools to interact with it. | | Supabase | Specific | | ------------------- | --------------------------------- | ------------------------------------------------ | | Agent integration | Not designed for agents | Agent-first | | Frontend deployment | Not included | Full service deployment | | Backend services | Only TypeScript edge functions | Any language and any framework | | Database access | Via `supabase-js` SDK or REST API | Standard Postgres connection, any ORM | | Auth | Built-in (Supabase Auth) | Use any auth library or service of your choosing | | Real-time | SDK-based subscriptions | Built-in sync engine that works with any stack | | Storage | SDK-based file storage | S3-compatible, any S3 client | | Local development | Supabase CLI (Docker-based) | `specific dev` (no Docker) | ## Designed for coding agents Supabase is built around a web dashboard and SDK documentation aimed at human developers. Setting up a project, configuring auth providers, and managing storage policies all happen through the dashboard. Specific is designed from the ground up so that coding agents can define, deploy, and troubleshoot your entire infrastructure. Your agent writes a config file, runs CLI commands, and gets structured feedback it can act on. No dashboard clicks needed to make infrastructure changes. Your infrastructure stays in sync with your code. ## No SDK required Supabase routes most interactions through its `supabase-js` SDK, like database queries, auth, file uploads, and real-time subscriptions. Your application code becomes tightly coupled to this SDK. Specific exposes standard interfaces: a Postgres database, S3-compatible endpoints, and environment variables. You use whatever stack you prefer with no lock-in. ## Full-stack deployment, not just backend Supabase focuses on the backend layer. For your frontend, custom backend services, and background workers, you still need a separate deployment platform and need to manage the integration yourself. Specific deploys your entire stack, including frontend, backend API, and workers, from a single configuration. Everything is defined together and deployed together. ## Any language, any framework Supabase Edge Functions run Deno. If your backend needs a different runtime, you're on your own. With Specific, your services can be Node.js, Python, Go, Rust, or anything else. You pick the stack, Specific runs it. Clone an example project and get familiar with Specific Install Specific for your own project and get started building # Specific vs Terraform Source: https://docs.specific.dev/compare/terraform Terraform is an infrastructure-as-code tool for defining cloud resources in HCL. It only manages infrastructure, it doesn't build, deploy, or run your application. You need to set up a local dev environment, pick providers, wire them together, and build a deployment pipeline. Specific provides all this so you can focus on building your application instead of managing infrastructure. | | Terraform | Specific | | ---------------------- | ------------------------------------- | --------------------------------------------------------- | | Agent integration | Not designed for agents | Agent-first with built-in context | | Local development | No local dev environment | `specific dev` runs everything locally | | Infrastructure | Assemble and wire providers yourself | Built-in Postgres with sync engine, object storage, Redis | | Application deployment | Separate CI/CD needed | Full build and deploy pipeline | | Automatic deploys | Requires external CI/CD setup | Built-in GitHub integration | | State management | State files you must store and manage | Handled automatically, no state files | ## Local development that matches production Terraform has no local development story. If you want to develop against a database, storage, or cache locally, you're on your own setting that up and keeping it in sync with your Terraform definitions. With Specific, `specific dev` starts your entire stack in a single command: databases, storage, Redis, and your services. The local environment uses the same config as production, so what works locally works when you deploy. Even better, your agent can run `specific dev` itself and test your entire app end-to-end. ## Building blocks that fit together With Terraform, you pick a cloud provider, find the right provider plugins, configure each resource, and wire them together with references, outputs, and data sources. Getting a database, storage bucket, and application to talk to each other takes dozens of lines of configuration across multiple files. Specific provides the building blocks your application needs and they work together out of the box. Connection strings, credentials and wiring are automatically configured by your coding agent and handled by our deployment pipeline. ## Built for coding agents Terraform was built for human operators managing cloud infrastructure. It assumes your agent will know how to write correct configurations for any provider and you will have to set up your own workflows to manage state files and deployment pipelines. Specific is designed for coding agents. The CLI provides structured feedback that agents can act on and ships with built-in documentation context so your agent can define infrastructure, deploy, and troubleshoot without leaving the terminal. ## From code to production, including GitHub deploys Terraform stops at infrastructure provisioning. To actually build and deploy your application, you need a separate CI/CD pipeline, container registry, and deployment tooling. Specific handles the full pipeline: build, deploy, and run. Connect your GitHub repository and get automatic deploys on every push. No separate CI/CD to configure, no container registry to manage. ## No state files to manage Terraform tracks every resource in a state file. You need to store this state somewhere safe, set up locking so concurrent runs don't corrupt it, and deal with drift when someone changes infrastructure outside of Terraform. Specific manages all state internally. There are no state files to store, lock, or reconcile. Clone an example project and get familiar with Specific Install Specific for your own project and get started building # Specific vs Vercel Source: https://docs.specific.dev/compare/vercel Vercel is a deployment platform optimized for frontend frameworks, especially Next.js. It handles builds, edge functions, and CDN distribution well. But for infrastructure beyond the frontend, like databases, object storage, background workers, and service-to-service communication, you need to assemble third-party services and manage them separately. Specific provides all of these as composable building blocks, defined in a single config file by your coding agent. | | Vercel | Specific | | ------------------------- | ----------------------------- | ----------------------------------------------- | | Agent integration | Dashboard-first | Agent-first | | Frontend deployment | Optimized for Next.js/React | Any framework, any language (including Next.js) | | Backend services | Serverless/edge functions | Full services (long-running, any runtime) | | Database | Third-party integrations | Built-in managed Postgres | | Object storage | Third-party (Vercel Blob) | Built-in S3-compatible storage | | Caching | Third-party (Vercel KV) | Built-in managed Redis | | Real-time | Not included | Built-in sync engine | | Background jobs | Limited cron, no long-running | Full worker services | | Infrastructure definition | Dashboard + framework config | Config file, agent-writable | ## Agent-first, not dashboard-first Vercel's primary interface is a web dashboard with git-based deployments configured through the UI. Project settings, environment variables, and domain configuration all live in the dashboard. This works for human developers, but it's a dead end for coding agents. Specific is designed so that coding agents define and manage everything through a config file and CLI commands. Infrastructure changes are a config edit away, not a dashboard click. Your agent gets structured feedback from every command, making it easy to iterate, troubleshoot, and deploy without leaving the terminal. ## Full-stack infrastructure, not just frontend Vercel focuses on the frontend layer and relies on third-party integrations for databases, storage, and queues. Each integration comes with its own dashboard, billing, SDK, and documentation. Your coding agent needs to understand multiple platforms to build a full application. Specific provides all the building blocks in one place: services, Postgres databases, S3-compatible storage, Redis, and a real-time sync engine. Everything is defined in a single config file and managed through a single CLI. One platform for your agent to learn, one place to troubleshoot. ## Not limited to serverless or specific frameworks Vercel is optimized for Next.js and serverless functions with execution time limits and cold starts. If your backend needs long-running processes, WebSocket connections, or a language other than JavaScript, you hit the edges of what Vercel supports. Specific deploys full services like backend APIs, background workers, and WebSocket servers in any language. There are no execution time limits or cold starts. Your services run as long-running processes with the resources they need. ## Local development parity Vercel doesn't provide a unified local development environment for your full stack. You run `next dev` for the frontend, but databases, storage, and other services need to be managed separately, often pointing at remote development instances or running Docker containers manually. With Specific, `specific dev` starts everything in a single command: databases, storage, Redis, and your services. The local environment uses the same config as production, so what works locally works when you deploy. Clone an example project and get familiar with Specific Install Specific for your own project and get started building # Dashboard Source: https://docs.specific.dev/concepts/dashboard Observe and manage your deployed projects, with a local counterpart during development. The [dashboard](https://dashboard.specific.dev) is where you observe and manage everything you've deployed. Log in with the same account you use for `specific deploy`; your projects and environments appear automatically after the first deployment. ## What you can do * **Service overview** - architecture visualization, per-service status, logs, metrics, and scaling. * **Deployments** - view and track deployments across environments. * **Database** - browse tables, run queries, and manage your Postgres databases. * **Storage** - browse bucket contents and generate external S3 credentials. * **Secrets and config** - update values in place; they take effect on the next deployment. * **Crons** - inspect scheduled jobs and their runs, or trigger one with **Run now**. * **Workflows** - the Temporal Web UI for your [Temporal](/guides/temporal) engines: monitor workflow executions, task queues, and workflow state. * **Analytics** - traffic analytics for your services. * **Jobs** - run [one-off commands](/guides/jobs) against a deployed service. * **Custom domains** - add, list, and remove [domains](/guides/domains). * **GitHub integration** - deploy automatically on every push and get [preview environments](/guides/previews) per pull request. Logs and metrics are also queryable from the CLI; see [Observability](/guides/observability). ## The local dashboard Local development has the same dashboard: `specific dev` launches a local mirror of it, usually at `http://localhost:3000` (the exact URL is printed at startup, and each [instance](/concepts/local-development#multiple-instances) run with `--key` gets its own). It drops the features that don't apply locally, like deployments, domains, and scaling, and keeps everything you need while building: the architecture view, database browser, storage browser, crons, and workflows. # Deployments Source: https://docs.specific.dev/concepts/deployments From source code to a running production environment in one command. `specific deploy` takes your project from local development to a fully running production environment: provisioning infrastructure, building your code, and rolling out services with a single command. ```bash theme={null} specific deploy ``` ## First deploy The first `specific deploy` walks you through a short setup: 1. **Login** - your browser opens to authenticate with Specific Cloud. The session is saved for future deploys. 2. **Project selection** - choose an existing project or create a new one. The project is saved to `.specific/project.json` so subsequent deploys skip this step. 3. **Deploy** - your project is built, infrastructure is provisioned, and services go live. After that, deploys are a single command with no prompts (unless new secrets or config values need to be set). ## The pipeline Verifies you are logged in to Specific Cloud. If not, your browser opens for login. Runs your build commands locally to catch errors before deploying, giving fast feedback without waiting for a cloud build. Your project code is uploaded to Specific Cloud. Your code is built in the cloud based on the [`build` blocks](/guides/builds) in `specific.hcl`. Multiple builds run in parallel, and dependencies are cached for faster rebuilds. If any [secrets or config values](/guides/secrets-and-config) are missing for the target environment, you are prompted to enter them. You can enter values while builds are still running. Databases, object storage, Redis, sync engines, and Temporal namespaces are provisioned as needed. Resources are created once and reused across deploys. Services are rolled out with zero downtime: new instances must pass their [health checks](/guides/services#health-checks) before receiving traffic. [Deploy hooks](/guides/services#deploy-hooks) run at this stage: `pre_deploy` before the service starts (a failed hook aborts the deployment), `post_deploy` after it's live. [Reshape migrations](/guides/reshape) are started before the rollout and completed after it succeeds. The deployment is live. Public URLs for your services are displayed in the terminal. If any step fails, the deployment is aborted and the error is shown in the terminal. Fix the issue and run `specific deploy` again. ## Public URLs Services with `endpoint { public = true }` get a public HTTPS URL on a managed `*.spcf.app` domain, shown in the terminal when the deploy completes. TLS is handled automatically. Services without a public endpoint are only reachable internally by other services. To serve a service from a domain you own, see [Custom domains](/guides/domains). ## Environments A project can have multiple environments (for example, `production` and `staging`), each with its own resources, secrets, and config. Target one with `specific deploy --environment `, and list them with `specific status`. [Preview environments](/guides/previews) are ephemeral environments created per pull request or with `specific deploy --preview`. ## Managing production Once deployed, the [dashboard](/concepts/dashboard) is your window into the project: logs and metrics, deployment history, database management, secrets, scaling, custom domains, and more. To deploy automatically on every push, connect your GitHub repository in the dashboard's settings. # How Specific works Source: https://docs.specific.dev/concepts/how-it-works The mental model: one config file that runs your whole system, locally and in production. Specific is infrastructure-as-code designed for coding agents. Your infrastructure is defined in a single `specific.hcl` file alongside your application code: how to build, run, and deploy the full system, in both development and production. Specific is fully generic: it works with any programming language and framework, without SDKs. All connection details reach your code through environment variables. ## One file, every environment A typical `specific.hcl`: ```hcl specific.hcl theme={null} build "app" { base = "node" command = "npm run build" } service "web" { build = build.app command = "npm start" endpoint { public = true } env = { PORT = port DATABASE_URL = postgres.main.url } dev { command = "npm run dev" } pre_deploy { command = "npm run db:migrate" } } postgres "main" {} ``` The same file drives every environment your project runs in: * **[`specific dev`](/concepts/local-development)** runs everything locally (Postgres, services, sync engines) with connection details injected automatically. No `.env` files. * **[`specific deploy`](/concepts/deployments)** builds the code, provisions managed infrastructure, and rolls out services to Specific Cloud. A project can have multiple deployed environments (production, staging, [previews](/guides/previews)), all defined by the same file. References like `postgres.main.url` resolve to the right value in each environment: a local database during development, a managed one per deployed environment. ## Building blocks | Block | What it defines | | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | [`build`](/guides/builds) | How to produce artifacts: managed base environments or custom Dockerfiles. | | [`service`](/guides/services) | Long-running processes: web apps, APIs, workers. | | [`cron`](/guides/crons) | Scheduled jobs with per-run logs and metrics. | | [`postgres`](/guides/postgres) | Managed PostgreSQL databases, with optional [Reshape](/guides/reshape) zero-downtime migrations and [real-time sync](/guides/sync). | | [`storage`](/guides/storage) | S3-compatible object storage. | | [`redis`](/guides/redis) | Redis-compatible caches (Valkey). | | [`temporal`](/guides/temporal) | Managed Temporal workflow engines for durable workflows. | | [`secret` / `config`](/guides/secrets-and-config) | Parameterized sensitive and environment-specific values. | | `volume` | [Persistent directories](/guides/volumes) inside services. | | `environment` | Per-environment [config overrides](/guides/secrets-and-config#environment-overrides). | ## The workflow Whether you're a human or a coding agent, working with Specific follows the same loop: 1. Create or edit `specific.hcl`. 2. Run `specific check` to validate the configuration - always, after every change. 3. Run `specific dev` to run the system locally, and `specific exec -- ` for one-off commands like migrations and seeding. 4. Run `specific deploy` to ship it. After deploying, manage the project from the [dashboard](https://dashboard.specific.dev): logs and metrics, scaling, database browsing, secrets, and custom domains. ## Designed for coding agents Your coding agent writes and maintains `specific.hcl`: you describe what you want to build, and the agent defines the infrastructure alongside the code. The CLI ships its own LLM-optimized documentation (`specific docs`), and `specific init` wires it into your agent's context. See [Coding agents](/coding-agents). # Local development Source: https://docs.specific.dev/concepts/local-development Run your complete system locally with a single command. `specific dev` starts everything your project needs locally with a single command: databases, caches, object storage, real-time sync, durable workflows, and application services. ```bash theme={null} specific dev ``` Specific reads `specific.hcl` and: 1. Installs and starts all required resources (Postgres, Redis, storage, sync, Temporal). 2. Starts your application services, using their `dev` commands where defined. 3. Launches the [local dashboard](/concepts/dashboard#the-local-dashboard). All connection details (database URLs, S3 credentials, ports) are injected into your services as environment variables. No `.env` files needed. The terminal output includes the URL of every service and the local dashboard. ## Ports Every service and resource gets its own local port, assigned automatically at startup. The local dashboard usually lands at `http://localhost:3000` with services on the ports next to it, and the exact URLs are printed when `specific dev` starts. Running several instances at once is fine; each gets its own set of ports. Reference ports with `port` (or `endpoint..port`) in `specific.hcl` and read them from the environment in your code. ## Config file watching While `specific dev` is running, changes to `specific.hcl` are detected automatically. As your coding agent updates the configuration, the environment reloads: new services start, removed services stop, and resource changes take effect without a manual restart. ## Service logs Each service's stdout and stderr are written to a per-service log file: ``` .specific/keys//logs/.log ``` Without `--key`, the path is `.specific/keys/default/logs/.log`. Each line is prefixed with an ISO-8601 timestamp and the stream it came from: ``` [2026-05-06T14:23:11.482Z] [stdout] Listening on port 3001 [2026-05-06T14:23:11.500Z] [stderr] warning: deprecated API ``` This makes logs easy for you or your coding agent to read or grep when debugging, instead of watching the live `specific dev` output: ```bash theme={null} tail -f .specific/keys/default/logs/api.log grep -i error .specific/keys/default/logs/api.log ``` Each file is capped at 1 MB. When a service produces more output, the file is truncated to the most recent \~512 KB on a line boundary, so the path is stable and always contains the latest logs. ## One-off commands Use `specific exec` to run commands with a service's environment: migrations, seeds, scripts. If `specific dev` is running, it reuses the running resources; otherwise it starts what's needed temporarily: ```bash theme={null} specific exec api -- npm run db:migrate ``` Use `specific psql` for an interactive database session, and `specific clean` to wipe local data for a fresh start. See the [CLI reference](/reference/cli). ## Multiple instances Run isolated dev environments side by side with `--key`. Each instance gets its own data and its own ports: ```bash theme={null} specific dev --key feature-auth ``` Each instance stores its state under `.specific/keys//`, so databases and other data are fully isolated. **Automatic git worktree detection:** when working in a git worktree, Specific uses the worktree name as the instance key automatically; no `--key` flag needed. ## Tunnel mode Expose your local services to the internet with `--tunnel`. Each public service gets a publicly reachable URL, useful for sharing work, testing webhooks, or letting a remote agent reach your machine: ```bash theme={null} specific dev --tunnel ``` Services are available at: ``` https://.tunnel.spcf.app ``` # Cache Source: https://docs.specific.dev/examples/cache A simple Node.js page counter demonstrating how to use Redis caching with Specific. Try it in your browser View on GitHub
Cache service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-cache-counter npm install ``` ```bash theme={null} specific dev ``` Open the URL shown in the output to see the counter increment on each visit. ```bash theme={null} specific deploy ``` # Database Source: https://docs.specific.dev/examples/database A simple Node.js notes API demonstrating PostgreSQL database persistence with Specific. Try it in your browser View on GitHub
Database service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-notes-api npm install ``` ```bash theme={null} specific dev ``` Open the URL shown in the output to access the API. ```bash theme={null} specific deploy ``` # Database with Sync Source: https://docs.specific.dev/examples/database-with-sync A minimal Node.js app demonstrating real-time sync across multiple clients using Specific's PostgreSQL sync engine. Try it in your browser View on GitHub
Database with Sync service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-realtime-click-counter npm install ``` ```bash theme={null} specific exec web -- npm run db:migrate specific dev ``` Open the `web` service URL printed in the terminal (usually [http://localhost:3001](http://localhost:3001)) to view the app. ```bash theme={null} specific deploy ``` # Durable Workflows Source: https://docs.specific.dev/examples/durable-workflows A task queue application demonstrating how to use Temporal for durable workflows, with a local Temporal server in development and Temporal Cloud in production. Try it in your browser View on GitHub
Durable Workflows service diagram ## How it works * **Development**: Runs a local Temporal server automatically via `specific dev` * **Production**: Connects to Temporal Cloud using configs and secrets ## Run locally Install the Temporal CLI from [https://docs.temporal.io/cli](https://docs.temporal.io/cli) ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-workflows npm install ``` ```bash theme={null} specific dev ``` Open the URL shown in the output to schedule tasks and view their status. Then deploy: ```bash theme={null} specific deploy ``` You will automatically be prompted to input secrets and config values for a Temporal Cloud API Key, namespace and address. # Hello World Source: https://docs.specific.dev/examples/hello-world A minimal Node.js HTTP server demonstrating the basics of deploying a service with Specific. Try it in your browser View on GitHub
Hello World service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-hello-api ``` ```bash theme={null} specific dev ``` Open the URL shown in the output to see the API response. ```bash theme={null} specific deploy ``` # Microservices Source: https://docs.specific.dev/examples/microservices A demonstration of how multiple services can communicate with each other using Specific's service reference syntax. Try it in your browser View on GitHub
Microservices service diagram * **Gateway** - Public-facing service that aggregates data from internal services * **Users** - Internal service that returns user data * **Products** - Internal service that returns product data ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-microservices npm install ``` ```bash theme={null} specific dev ``` Open the gateway URL shown in the output to see aggregated data from the internal services. ```bash theme={null} specific deploy ``` # Object Storage Source: https://docs.specific.dev/examples/object-storage A simple Node.js file uploader demonstrating how to work with a S3-compatible object storage in Specific. Try it in your browser View on GitHub
Object Storage service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-file-storage npm install ``` ```bash theme={null} specific dev ``` Open the URL shown in the output to access the file manager. ```bash theme={null} specific deploy ``` # Secrets and Configs Source: https://docs.specific.dev/examples/secrets-and-configs A simple example demonstrating how to use secrets and configs in Specific for managing sensitive and non-sensitive configuration. Try it in your browser View on GitHub
Secrets and Configs service diagram ## Run locally ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` ```bash theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-secrets npm install ``` ```bash theme={null} specific dev ``` You will be automatically prompted to input the secret and config values. Visit the URL in the output to see them in action. ```bash theme={null} specific deploy ``` # Builds Source: https://docs.specific.dev/guides/builds Define how your code is built: managed base environments or custom Dockerfiles. Builds define how to produce artifacts. Services and crons reference builds. ```hcl specific.hcl theme={null} build "api" { base = "node" command = "npm run build" } ``` ## Configuration One of the following is required (mutually exclusive): * `base` - base environment: `"node"`, `"python"`, `"go"`, `"rust"`, or `"java"`. For anything else, use a custom Dockerfile. * `dockerfile` - path to a custom Dockerfile, relative to `specific.hcl`. Optional fields: * `command` - build command to run after dependencies are installed (for example, `npm run build` or `go build -o api`). Only valid with `base`, not with `dockerfile`. * `root` - working directory for build commands, relative to `specific.hcl`. Defaults to `"."`. Sets the `WORKDIR` in the generated Dockerfile; services that reference this build inherit its root, and dependency detection looks here. * `context` - Docker build context scope, relative to `specific.hcl`. Defaults to `"."`. Controls what files are available to `COPY` and what's included in the deployment tarball. * `env` - environment variables available during the build, passed as Docker build args. See [Build-time environment variables](#build-time-environment-variables). ## Automatic dependency installation Specific detects your dependency manager (from the lockfile) and installs dependencies before running your build command. Installs are cached, so rebuilds are fast when only source code changes. For projects that only need dependencies installed, omit `command`: ```hcl specific.hcl theme={null} build "api" { base = "node" } ``` Run `specific docs builds` for the exact per-base detection and install behavior. ## Build-time environment variables Use `env` to pass variables during the build step. This is useful for frameworks like Next.js that inline environment variables at build time. ```hcl specific.hcl theme={null} build "web" { base = "node" command = "npm run build" env = { NEXT_PUBLIC_API_URL = "https://${service.api.public_url}/v1" NODE_ENV = "production" } } ``` Supported reference types: * String literals (for example, `"production"`). * `service..public_url` - the public domain of another service. * String interpolation with `${service..public_url}`. Since `public_url` doesn't include a scheme, use interpolation to compose full URLs. Other references (secrets, config, databases) are not available at build time. ## Monorepos Use `root` to set where build commands run. This applies to both the build command and dependency detection: ```hcl specific.hcl theme={null} build "backend" { base = "node" root = "packages/backend" command = "npm run build" } build "frontend" { base = "node" root = "packages/frontend" command = "npm run build" } ``` ### `root` vs `context` The two are orthogonal: * `root` = where commands run (working directory). * `context` = what files are available (Docker build context / tarball scope). By default, `context` is the `specific.hcl` directory. Set it only to widen the scope, for example to include shared libraries in a parent directory: ```hcl specific.hcl theme={null} # specific.hcl is in apps/myapp/, but shared libs are in libs/ build "api" { base = "node" root = "packages/api" context = "../" # Include parent dir so shared libs are available } ``` ## Custom Dockerfile For full control over the build, provide your own Dockerfile instead of `base`: ```hcl specific.hcl theme={null} build "api" { dockerfile = "Dockerfile" } ``` When using a custom Dockerfile: * `command` is not allowed - define build steps in the Dockerfile itself. * `context` still controls the Docker build context. * `env` vars are passed as Docker build args; consume them with `ARG` instructions. * The service `command` still overrides the container `CMD` at runtime. ```hcl specific.hcl theme={null} build "web" { dockerfile = "docker/Dockerfile.prod" context = "." env = { NEXT_PUBLIC_API_URL = service.api.public_url NODE_ENV = "production" } } ``` ```dockerfile Dockerfile theme={null} FROM node:20-slim ARG NEXT_PUBLIC_API_URL ARG NODE_ENV WORKDIR /app COPY . . RUN npm ci && npm run build CMD ["npm", "start"] ``` ## Local development The `dev` block overrides the build command during `specific dev`. If no `dev` block is defined, the build is skipped in development; most dev servers (like `npm run dev`) handle building themselves. ```hcl specific.hcl theme={null} build "spa" { base = "node" command = "npm run build" dev { command = "npm run build:watch" } } ``` For compiled languages (Go, Rust, Java), a `dev` block is almost always needed; without it, no binary is produced locally. Use a tool that rebuilds on file changes: ```hcl specific.hcl theme={null} build "api" { base = "go" command = "go build -o api ./cmd/api" dev { command = "go run ./cmd/api" } } ``` ## Production During `specific deploy`, builds run in the cloud in parallel, after a local test run catches errors early. See [Deployments](/concepts/deployments) for the full pipeline. # Crons Source: https://docs.specific.dev/guides/crons Scheduled jobs with tracked runs, logs, and metrics. A cron is a scheduled job: like a service, but instead of running continuously it runs a command on a recurring schedule. Each execution is a tracked **run** with its own logs and metrics. ```hcl specific.hcl theme={null} build "worker" { base = "node" command = "npm run build" } cron "daily-cleanup" { build = build.worker command = "npm run cleanup" schedule = "0 2 * * *" # 02:00 UTC every day env = { DATABASE_URL = postgres.main.url } } postgres "main" {} ``` A cron is shaped like a service: it has its own `build` (or `image`), `command`, `env`, and `root`. To share code between a long-running service and a cron, point both at the same `build` block. ## Configuration * `schedule` (required) - when to run. Either a standard 5-field cron expression (`minute hour day-of-month month day-of-week`, interpreted in **UTC**) or a macro: `@hourly`, `@daily`, `@weekly`, `@monthly`, `@yearly`. * `build` - reference to a `build` block. Mutually exclusive with `image`. * `image` - a pre-existing container image. Mutually exclusive with `build`. * `command` - the command to run on each tick. Required when using `build`. * `root` - working directory for the command, relative to `specific.hcl`. Defaults to the referenced build's `root`. * `env` - environment variables, using the same references as services (`postgres.*`, `secret.*`, `config.*`, `service..private_url`, interpolated strings, and so on). * `dev` - a `{ command, env }` block to override the command and env when running the cron locally. Crons don't serve network traffic, so they cannot declare `endpoint`, `volume`, or `health_check` blocks. ### Schedule examples ```hcl theme={null} schedule = "0 2 * * *" # 02:00 every day schedule = "*/15 * * * *" # every 15 minutes schedule = "0 9 * * 1" # 09:00 every Monday schedule = "@hourly" # top of every hour schedule = "@daily" # midnight every day ``` ### Image-based crons A cron can run a pre-existing image instead of a build: ```hcl specific.hcl theme={null} cron "hourly-sync" { image = "python:3.12" command = "python /app/sync.py" schedule = "@hourly" } ``` ## Local development Crons do **not** fire on their schedule during `specific dev`, since that would be surprising while iterating. Instead, trigger a cron manually, exactly like a one-off command: ```bash theme={null} specific exec daily-cleanup # runs the cron's own command specific exec daily-cleanup -- npm run cleanup:dry-run # run a different command ``` The command runs with the cron's resolved environment variables and working directory, with databases and other resources started, the same way `specific exec ` works. Crons are also listed in the [local dashboard](/concepts/dashboard#the-local-dashboard) (`specific dev` prints its URL) under **Crons**. ## Production When deployed, each cron runs on its schedule in the cloud. Every execution is a tracked run: * Runs are visible in the [dashboard](https://dashboard.specific.dev) under **Crons → (cron) → runs**. * Each run has its own logs and CPU/memory metrics, collected the same way as services. * Overlapping runs are allowed - if a run is still going when the next is due, the next one starts anyway. * You can trigger a run on demand with the **Run now** button. # Custom domains Source: https://docs.specific.dev/guides/domains Serve your services from domains you own, with automatic TLS. By default, every public service gets a managed `*.spcf.app` URL. To serve a service from a domain you own, attach a custom domain to it. ## Attach a custom domain Deploy the service first, then run: ```bash theme={null} specific domain add ``` For example: ```bash theme={null} specific domain add web api.example.com ``` The command prints the DNS records to configure at your registrar. The DNS change is the one step Specific can't do for you. By default the command targets the environment linked in your project directory (set by the most recent `specific deploy`). To target a different environment, pass `--environment`: ```bash theme={null} specific domain add web api.example.com --environment staging ``` ## DNS records The output includes two options; pick one based on what your DNS provider supports: * **CNAME** - recommended for subdomains (`api.example.com`, `app.example.com`). Points the subdomain at `ingress.specific.dev`. * **A record** - recommended for apex domains (`example.com`), since most DNS providers don't allow CNAMEs at the zone apex. Points the domain at one of three Specific ingress IPs (any one works; the output shows one). TLS certificates are issued automatically via Let's Encrypt once DNS resolves to Specific's ingress. There is no separate verification step: configure DNS and wait a few minutes. ## Confirming the domain Adding a domain registers it with Specific, but doesn't verify that DNS is configured correctly or that TLS has been issued. To verify end-to-end once DNS is configured: ```bash theme={null} curl https:// ``` ## Managing domains in the dashboard Custom domains can also be added, listed, and removed in the [dashboard](https://dashboard.specific.dev). The dashboard is currently the only way to **remove** a custom domain; there is no `specific domain remove` command. # Jobs Source: https://docs.specific.dev/guides/jobs Run one-off commands against a deployed service in production. A **job** is a single execution of a user-supplied command inside a one-off container built from the currently-running service. The container uses the same image, environment variables, and resources as the service's live deployment; only the command is different. Jobs are the remote equivalent of [`specific exec`](/reference/cli#specific-exec). Where `specific exec` runs a one-off command against your local dev environment, a job runs against the deployed service in production (or any other environment). Use them for ad-hoc, on-demand work such as: * One-off data backfills or corrections. * Reconciling state, purging a cache, or replaying a queue. * Running a debugging or diagnostic script against production data. **Don't use jobs for database migrations.** Migrations should run in a [`pre_deploy` hook](/guides/services#deploy-hooks) so they're tied to the deployment lifecycle: the hook runs before the new service version starts, and if it fails, the deployment is aborted before any traffic reaches the new code. Jobs are decoupled from deployments and have no such safety net. ## Running a job Open the [dashboard](https://dashboard.specific.dev), navigate to a service, and open the **Jobs** tab. Click **Run job**, fill in an optional name and a command, and submit. You are redirected to the job's detail page, where you can watch its state and stream logs in real time. The command runs in a shell, so pipes and `&&` work. Because the job is built from the service's live deployment, it always sees the same secrets, configs, and resource bindings as the running service. There is no drift between what the service runs with and what the job runs with. Re-running a previous job pre-fills the modal with its name and command, convenient for replaying a task after fixing a bug. ## Lifecycle A job transitions through the following states: 1. `pending` - the job has been recorded. 2. `queued` - the job's workflow has been started. 3. `running` - the job container is running. 4. One of: * `succeeded` - the command exited with code `0`. * `failed` - the command exited with a non-zero code, or the underlying infrastructure rejected the job. * `cancelled` - the job was cancelled via the dashboard before it finished. ## Caveats * **The service must be deployed.** A job builds its container from the service's live deployment; if the service has never been deployed, the job fails with a clear error. * **No retries on failure.** If the command exits non-zero, the job is marked `failed`. Start a new job (or re-run) to try again. * **Single container only.** Sidecars and init containers are not replicated - only the primary container runs. * **Concurrent jobs are allowed.** Multiple jobs can run at the same time against the same service; be mindful of shared state. * **Volume contention.** If the service mounts a single-writer volume and runs on different underlying hardware than the job, the job can fail to schedule. * **Job records are cleaned up one hour after completion.** Logs remain queryable for the standard [retention window](/guides/observability#schema). # Observability Source: https://docs.specific.dev/guides/observability Query your environments' logs and metrics with SQL. Every deployed environment streams logs and metrics into a queryable store. Use `specific query` to run SQL against this data when debugging production incidents, investigating regressions, or doing ad-hoc analytics. ## Running a query ```bash theme={null} # Inline specific query "SELECT count() FROM observability.logs" # Against a specific environment specific query --environment staging "SELECT * FROM observability.logs LIMIT 5" # From a file via stdin cat queries/p99.sql | specific query # Machine-readable output for agents and scripts specific query --format jsonl "SELECT Timestamp, Body FROM observability.logs LIMIT 5" ``` Flags: | Flag | Description | | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-e, --environment ` | Target environment by name or ID (defaults to the current one). Run `specific status` to list environments. | | `--db ` | Run the query against one of the environment's **Postgres databases** (read-only) instead of the observability store. The SQL is standard Postgres, and the schema is your application's tables; see [Postgres](/guides/postgres). | | `--format ` | Output format. Defaults to `table` on a terminal, `jsonl` when piped. | Queries are automatically scoped to the selected environment: you can't see data from other environments and don't need to filter on environment yourself. Queries are read-only: `INSERT`, `UPDATE`, `DELETE`, and DDL are rejected. Each query is capped at 30 seconds of execution time, returns at most 100,000 rows, and the SQL string is limited to 50,000 characters. The `table` format truncates wide values for readability. Agents and scripts should use `jsonl`, `json`, or `csv` for complete, untruncated values. Notices are printed to stderr so stdout remains parseable. ## Choosing an environment `specific query` runs against exactly one environment. Run `specific status` to discover every environment and its ID. The output has two sections: * **Environments** - long-lived environments such as `production` and `staging`. * **Preview environments** - ephemeral environments created for pull requests (plus any manually created previews), each with its name, `env_...` ID, PR number and title, deployed URL, and expiry. Preview environments stream logs and metrics exactly like long-lived ones. To inspect one, pass its name or ID to `--environment`; that's the only way to reach a preview's data, since queries are auto-scoped: ```bash theme={null} specific query --environment preview-a1b2c3d4 \ "SELECT Timestamp, ServiceName, Body FROM observability.logs WHERE SeverityNumber >= 17 ORDER BY Timestamp DESC LIMIT 50" ``` ## Schema Two views are exposed in the `observability` database. Column names follow OpenTelemetry's ClickHouse exporter conventions and are **case-sensitive**, so use `SeverityText`, `ServiceName`, and `ResourceAttributes` exactly as shown. If unsure, run `DESCRIBE observability.logs`. ### observability.logs Unified log stream from services. Retention: up to 30 days (your plan may restrict how far back queries can read; a cutoff prints a note on stderr). | Column | Type | Notes | | -------------------- | ------------------- | ------------------------------------------------------------------------------------------- | | `Timestamp` | DateTime64(9) | When the log was emitted; supports time arithmetic (`Timestamp > now() - INTERVAL 1 HOUR`). | | `ServiceName` | String | Service that emitted the log. | | `SeverityText` | String | | | `SeverityNumber` | UInt8 | | | `Body` | String | The log message. | | `LogAttributes` | Map(String, String) | Per-event attributes. | | `ResourceAttributes` | Map(String, String) | Resource labels (for example, `service.name`, `deployment.environment.name`). | | `TraceId` | String | Distributed-tracing trace ID, if present. | | `SpanId` | String | Distributed-tracing span ID, if present. | Also exposed but rarely queried directly: `EnvironmentId`, `ProjectId` (used for auto-scoping), `TraceFlags`. ### observability.metrics Unified metrics from services. Retention: up to 90 days. | Column | Type | Notes | | -------------------- | ------------------- | ------------------------------------------------ | | `TimeUnix` | DateTime64(9) | Measurement timestamp; supports time arithmetic. | | `MetricName` | String | For example, `container.cpu.time` (see below). | | `MetricType` | String | `'gauge'` or `'sum'`. | | `Value` | Float64 | Measured value. | | `ServiceName` | String | Service that emitted the metric. | | `Attributes` | Map(String, String) | Metric dimensions. | | `ResourceAttributes` | Map(String, String) | Resource labels. | ### Service metrics Emitted for every running service container: | Metric | Type | Notes | | --------------------------------- | ----- | ---------------------------------------------------------------------------------- | | `container.cpu.time` | sum | Cumulative CPU seconds; rate it for utilization. | | `container.cpu.usage` | gauge | Current CPU usage in cores. | | `container.cpu.limit_utilization` | gauge | Fraction of CPU limit used (0–1). | | `container.memory.working_set` | gauge | Memory in active use (bytes), the right number for "is this service close to OOM". | | `container.memory.usage` | gauge | Total memory usage including page cache (bytes). | | `container.memory.available` | gauge | Memory available before the container limit (bytes). | | `k8s.volume.available` | gauge | Free space on attached volumes (bytes). | | `k8s.volume.capacity` | gauge | Total capacity of attached volumes (bytes). | ## Debugging recipes Recent errors for a service: ```sql theme={null} SELECT Timestamp, Body FROM observability.logs WHERE ServiceName = 'api' AND SeverityNumber >= 17 AND Timestamp >= now() - INTERVAL 1 HOUR ORDER BY Timestamp DESC LIMIT 50 ``` Search log bodies for a substring: ```sql theme={null} SELECT Timestamp, ServiceName, Body FROM observability.logs WHERE positionCaseInsensitive(Body, 'connection refused') > 0 AND Timestamp >= now() - INTERVAL 6 HOUR ORDER BY Timestamp DESC LIMIT 100 ``` Service CPU timeseries in 1-minute buckets: ```sql theme={null} SELECT toStartOfMinute(TimeUnix) AS bucket, avg(Value) AS cpu_cores FROM observability.metrics WHERE MetricName = 'container.cpu.usage' AND ServiceName = 'api' AND TimeUnix >= now() - INTERVAL 1 HOUR GROUP BY bucket ORDER BY bucket ``` Correlate all logs belonging to one trace: ```sql theme={null} SELECT Timestamp, ServiceName, Body FROM observability.logs WHERE TraceId = '' ORDER BY Timestamp ``` ## Performance Both views are partitioned and ordered to make environment-scoped, time-bounded queries fast. To stay within the 30-second limit: * **Always filter by time** - `Timestamp >=` for logs, `TimeUnix >=` for metrics. Unbounded scans across 30/90 days will time out. * **Add `ServiceName` and/or `MetricName`** to narrow the partition whenever you can. * **Select only the columns you need** - `Body`, `LogAttributes`, and `ResourceAttributes` are the heavyweight columns. * **`LIMIT` exploratory queries** while shaping them. ## Discovering data When you don't know what's there, ask the database: ```sql theme={null} SHOW TABLES FROM observability; DESCRIBE observability.logs; SELECT DISTINCT ServiceName FROM observability.logs LIMIT 50; SELECT DISTINCT MetricName FROM observability.metrics LIMIT 100; ``` ## ClickHouse dialect The observability store is ClickHouse, so `specific query` without `--db` uses the ClickHouse SQL dialect (unlike `--db`, which is standard Postgres). Commonly needed functions: * `now()`, `now64()` - current time * `toStartOfMinute(t)`, `toStartOfFiveMinutes(t)`, `toStartOfHour(t)` - bucket timestamps * `positionCaseInsensitive(haystack, needle)` - case-insensitive substring search * `JSONExtractString(s, 'field')`, `JSONExtractInt`, `JSONExtractFloat` - pull fields out of JSON log bodies * `LogAttributes['key']`, `Attributes['key']`, `ResourceAttributes['key']` - read map columns # Postgres Source: https://docs.specific.dev/guides/postgres Managed PostgreSQL databases, locally and in production. Managed PostgreSQL database instances, powered by [Neon](https://neon.tech) in production. One line in `specific.hcl` gives you a local database during `specific dev` and a managed production database on deploy. ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { DATABASE_URL = postgres.main.url } } postgres "main" {} ``` ## Connection attributes Reference these in `env` blocks: | Attribute | Description | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `url` | Full connection string (for example, `postgres://user:pass@host:5432/dbname`). | | `host` | Database host. | | `port` | Database port. | | `user` | Database user. | | `password` | Database password. | | `name` | Database name. | | `direct_url` | Non-pooled connection string, bypassing the connection pooler. Use when you need a direct connection (for example, Prisma's `directUrl`). | | `direct_host` | Non-pooled database host. | ## Extensions The following PostgreSQL extensions are available in both development and production. Enable each with `CREATE EXTENSION` in a migration: | Extension | Enable with | Use for | | -------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------ | | [pgvector](https://github.com/pgvector/pgvector) | `CREATE EXTENSION vector;` | Vector similarity search. | | [pg\_search](https://docs.paradedb.com/documentation/getting-started/quickstart) | `CREATE EXTENSION pg_search;` | Full-text search with BM25 ranking, powered by ParadeDB. | | [PostGIS](https://postgis.net/documentation/) | `CREATE EXTENSION postgis;` | Geospatial queries and indexing. | | [pg\_trgm](https://www.postgresql.org/docs/current/pgtrgm.html) | `CREATE EXTENSION pg_trgm;` | Trigram-based fuzzy text matching and `LIKE`/`ILIKE` indexes. | | [ltree](https://www.postgresql.org/docs/current/ltree.html) | `CREATE EXTENSION ltree;` | Hierarchical structures: categories, org charts, taxonomies. | | [pgRouting](https://docs.pgrouting.org/) | `CREATE EXTENSION pgrouting CASCADE;` | Routing and network analysis (requires PostGIS, installed by `CASCADE`). | For graph-shaped workloads, use `ltree` for hierarchies and `pgrouting` for weighted networks and shortest-path queries. Apache AGE and Cypher queries are not supported. ## Querying the database ### Local development Use `specific psql` to connect to a development database. The database is started automatically if it isn't running. ```bash theme={null} # Interactive session specific psql main # Run a single query specific psql main -- -c "SELECT * FROM users LIMIT 5" # List tables specific psql main -- -c "\dt" ``` ### Production Use `specific query --db ` to run read-only Postgres SQL against a deployed environment's database: ```bash theme={null} # Query the production "main" database specific query --db main "SELECT * FROM users LIMIT 5" # Target a specific environment with machine-readable output specific query --db main --environment staging --format jsonl \ "SELECT id, email FROM users ORDER BY created_at DESC LIMIT 20" ``` Production queries are **read-only**: `INSERT`, `UPDATE`, `DELETE`, and DDL are rejected (the query runs inside a read-only transaction). Without `--db`, `specific query` targets [observability data](/guides/observability) instead. You can also browse data and manage the database from the [dashboard](https://dashboard.specific.dev). ## Schema migrations For zero-downtime schema migrations, enable Reshape: ```hcl specific.hcl theme={null} postgres "main" { reshape { enabled = true } } ``` See [Reshape migrations](/guides/reshape) for how migrations are written and managed. If you prefer your ORM's migration tooling instead, run it via a `pre_deploy` hook; run `specific docs integrations/prisma` or `specific docs integrations/drizzle` for setup guidance. ## Real-time sync Postgres changes can be streamed to clients in real time. See [Real-time sync](/guides/sync). ## Preview environments In [preview environments](/guides/previews), databases are branched copy-on-write from the parent environment, so previews start with real data instantly. # Preview environments Source: https://docs.specific.dev/guides/previews Temporary, fully isolated copies of an environment, with real data. A preview environment is a temporary, fully isolated copy of an existing environment. It runs the same services with their own URLs and their own network namespace, on top of its own copy of the parent's stateful data, so a change can be tested end to end without touching the parent. ## How previews are created * **Per pull request** - with the GitHub integration connected, Specific creates a preview environment for each open pull request, keeps it up to date as new commits are pushed, and posts its URL back on the PR. Connect GitHub from the [dashboard](https://dashboard.specific.dev). * **Manually** - deploy one on demand with `specific deploy --preview`. Preview environments are ephemeral: pull-request previews are removed when the PR is closed or merged, and a preview can be given an expiry, after which Specific cleans it up automatically. Run `specific status` to list every environment and its `env_...` ID, including preview environments. Target a preview with `--environment` on commands that take one. ## What's copied from the parent A preview branches off a parent environment and starts from its data. Each resource is forked in the way that's fastest for that service: * **Postgres** databases are branched - an instant, copy-on-write branch. * **Object storage** buckets are forked. * **Volumes** are cloned - an instant, copy-on-write copy of the parent volume. The preview gets its own isolated database, buckets, and volumes; writing to them never affects the parent. A volume clone is an exact replica of the parent's on-disk data (uploads, caches, and search indexes alike), so the preview's service boots on it exactly as it would after a restart, with no extra configuration. ## Observability Previews stream logs and metrics exactly like long-lived environments. Query them by targeting the preview with `--environment`: ```bash theme={null} specific query --environment preview-a1b2c3d4 \ "SELECT Timestamp, Body FROM observability.logs ORDER BY Timestamp DESC LIMIT 50" ``` See [Observability](/guides/observability) for the full query reference. # Redis Source: https://docs.specific.dev/guides/redis Managed Redis-compatible caching, backed by Valkey. Managed Redis-compatible cache instances. Backed by [Valkey](https://valkey.io), the BSD-3-Clause open-source fork of Redis 7.2, so it works with any Redis client (`ioredis`, `node-redis`, `redis-cli`). ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { REDIS_URL = redis.cache.url } } redis "cache" {} ``` ## Connection attributes | Attribute | Description | | ---------- | -------------------------------------------------------------------- | | `url` | Full connection string (for example, `redis://:password@host:6379`). | | `host` | Redis host. | | `port` | Redis port. | | `password` | Redis password. | ## Local development and production During `specific dev`, a local Valkey instance runs automatically. In production, Specific provisions a managed instance; the same `redis.*` references resolve to it, with no code changes. # Reshape migrations Source: https://docs.specific.dev/guides/reshape Zero-downtime database schema migrations, managed automatically. Zero-downtime schema migrations using [Reshape](https://github.com/fabianlindfors/reshape), built into Specific. Reshape uses a 3-phase approach so old and new application code can run against the database at the same time: 1. **Start** - creates the new schema version with views and triggers. Both old and new schemas are available simultaneously. 2. **Rollout** - new application code is deployed and uses the new schema via `search_path`. 3. **Complete** - the old schema and migration artifacts are removed. ## Enabling Reshape Add a `reshape` block to a postgres definition in `specific.hcl`: ```hcl specific.hcl theme={null} postgres "main" { reshape { enabled = true } } ``` With a custom migrations directory (the default is `migrations/`, relative to `specific.hcl`): ```hcl specific.hcl theme={null} postgres "main" { reshape { enabled = true migrations_dir = "db/migrations" } } ``` ## Writing migrations Migrations are TOML files composed of actions (`create_table`, `add_column`, `alter_column`, `add_index`, `custom`, and more), processed in **lexical order** (`001_first.toml` before `002_second.toml`): ```toml migrations/001_create_users.toml theme={null} [[actions]] type = "create_table" name = "users" primary_key = ["id"] [[actions.columns]] name = "id" type = "INTEGER" generated = "ALWAYS AS IDENTITY" [[actions.columns]] name = "email" type = "TEXT" nullable = false ``` Run `specific check` every time you create or edit a migration file. It validates both `specific.hcl` and all migration files, catching errors before they're applied. Without it, invalid migrations silently fail to apply. The full list of actions, with every option and examples, is bundled with the CLI: run `specific docs postgres/reshape/actions`, and `specific docs postgres/reshape/actions/` for a specific one. ## Automatic management in development When `specific dev` starts with Reshape enabled, migrations are managed for you: 1. **All migrations except the last are completed** - these become permanent schema changes. 2. **The last migration is started but not completed** - so you can iterate on it. 3. **Completed migration files are made read-only** - preventing accidental modification. While `specific dev` is running: * **Modifying the last migration file** aborts and restarts that migration. Services keep running - no restart needed, since the schema name doesn't change. * **Adding a new migration file** completes the previous migration (making it permanent) and starts the new one. Services are restarted to use the new schema. The development workflow: 1. Write a migration file in the migrations directory. 2. Run `specific check` to validate. 3. `specific dev` applies it automatically. 4. Iterate on the migration - run `specific check` after **every** change. 5. When ready, add a new migration file to lock in the previous one. If you need to modify a completed migration, change its file permissions first; completed files are read-only on purpose. ## Connection strings When Reshape is enabled, `postgres..url` automatically includes the correct `search_path`. No service configuration changes needed: ```hcl specific.hcl theme={null} service "api" { build = build.api command = "node server.js" env = { DATABASE_URL = postgres.main.url # Automatically includes search_path } } ``` ## Manual migration commands You can also control migrations directly: ```bash theme={null} # Validate migration files (works without specific dev running) specific reshape check # Start a migration (applies new schema while keeping the old one available) specific reshape start # Check migration status on a specific database specific reshape status main # Complete a migration (removes old schema) specific reshape complete main # Abort a migration (rolls back to old schema) specific reshape abort main ``` Most actions need database access; if `specific dev` isn't running, the database is started temporarily. `check` only validates file syntax and runs anytime. ## Production During `specific deploy`, migrations follow the same 3-phase flow, coordinated with the service rollout: pending migrations are started before the new code rolls out, and completed once the rollout succeeds. If the rollout fails, the migrations are aborted automatically and the database rolls back to the old schema. # Secrets and config Source: https://docs.specific.dev/guides/secrets-and-config Parameterize sensitive and environment-specific values without hardcoding them. Secrets and config let you parameterize values that services need, instead of hardcoding them in `specific.hcl`: * **Secrets** - sensitive information that should never be committed to version control: API keys, database passwords, signing keys. * **Config** - non-sensitive values that may vary between environments: log levels, feature flags, URLs. Because every value is declared in `specific.hcl`, Specific knows exactly which ones are missing and prompts you for them when needed, both when starting `specific dev` and when deploying to the cloud. There's no `.env` file to assemble by hand. ## Secrets Declare the secrets your application needs and reference them in `env`: ```hcl specific.hcl theme={null} secret "stripe_api_key" {} secret "jwt_secret" { generated = true } service "api" { build = build.api command = "./api" endpoint { public = true } env = { STRIPE_API_KEY = secret.stripe_api_key JWT_SECRET = secret.jwt_secret } } ``` Secret fields: * `generated` - when `true`, auto-generates a random string if no value is set. Useful for internal secrets like JWT signing keys. * `length` - length of generated secrets (default: 64). Only applies when `generated = true`. Manual secrets (no `generated` flag) must be given a value: locally in `specific.local`, in production during deployment. Generated secrets are auto-created on first run, and you can still override them manually. Secret and config references cannot be interpolated into strings; use them as standalone `env` values. ## Config ```hcl specific.hcl theme={null} config "log_level" { default = "info" } service "api" { build = build.api command = "./api" endpoint { public = true } env = { LOG_LEVEL = config.log_level } } ``` Config fields: * `default` - value used unless overridden by an environment or locally. ### Environment overrides Override config values per environment with `environment` blocks: ```hcl specific.hcl theme={null} config "log_level" { default = "info" } environment "production" { config = { log_level = "warn" } } environment "staging" { config = { log_level = "debug" } } ``` ## Local development: `specific.local` Local secret and config values live in `specific.local`, a gitignored HCL file next to `specific.hcl`: ```hcl specific.local theme={null} secrets { stripe_api_key = "sk_test_..." } config { log_level = "debug" } ``` You don't have to fill it out ahead of time: `specific dev` prompts for any missing secrets and config values on startup. The file is never included in deployments. ## Production During `specific deploy`, the CLI checks that every required value is set for the target environment and prompts you interactively for anything missing. You can enter values while builds are still running. Values can also be passed as flags: `specific deploy --secret stripe_api_key=sk_live_...`. * Secrets are stored securely, never logged, and injected into services as environment variables at runtime. * Secrets are scoped per environment - setting a secret for `staging` does not affect `production`. * Update secrets and config anytime from the [dashboard](https://dashboard.specific.dev), without touching `specific.hcl`. New values take effect on the next deployment. ## Complete example ```hcl specific.hcl theme={null} # External API key: must be set manually, sensitive secret "stripe_api_key" {} # Internal signing key: auto-generated, sensitive secret "jwt_secret" { generated = true } # Log level: not sensitive, varies by environment config "log_level" { default = "info" } service "api" { build = build.api command = "./api" endpoint { public = true } env = { STRIPE_API_KEY = secret.stripe_api_key JWT_SECRET = secret.jwt_secret LOG_LEVEL = config.log_level } } environment "production" { config = { log_level = "warn" } } ``` # Services Source: https://docs.specific.dev/guides/services Define how your code runs and how it connects to everything else, in development and production. Services define how to run your code and connect it to other parts of your infrastructure, both in production and in local development. All configuration reaches your app through environment variables, and the same `specific.hcl` drives `specific dev` locally and `specific deploy` in production. A typical setup with a public frontend and API: ```hcl specific.hcl theme={null} build "web" { base = "node" command = "npm run build" } service "web" { build = build.web command = "npm start" endpoint { public = true } env = { PORT = port API_URL = "https://${service.api.public_url}" } dev { env = { API_URL = "http://${service.api.public_url}" } } } build "api" { base = "go" command = "go build -o api" } service "api" { build = build.api command = "./api" endpoint { public = true } env = { PORT = port } } ``` * `command` - command to start the server. * `root` - working directory for service commands, relative to `specific.hcl`. Defaults to the referenced build's `root`, or `"."` if no build. * `endpoint` - defines a network endpoint (see below). * `port` - reference to the auto-assigned port; pass it to your server. See [Builds](/guides/builds) for the `build` block. ## Endpoints Endpoints define how a service is accessible over the network. ### Single endpoint ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { PORT = port } } ``` * `public = true` makes the endpoint publicly accessible via HTTPS. * Omitting `public` (or `public = false`) keeps the endpoint internal-only. Public services are served from a managed `*.spcf.app` URL by default. To attach your own domain, see [Custom domains](/guides/domains). ### Multiple named endpoints A service can expose multiple endpoints on different ports, each independently public or internal: ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint "main" { public = true } endpoint "admin" {} env = { MAIN_PORT = endpoint.main.port ADMIN_PORT = endpoint.admin.port } } ``` With multiple endpoints, use `endpoint..port` instead of `port` to reference each endpoint's port. ### Implicit endpoints If a service uses `port` in its env vars but has no explicit endpoint blocks, an implicit internal endpoint is created: ```hcl specific.hcl theme={null} service "worker" { build = build.worker command = "./worker" env = { PORT = port # Creates an implicit internal endpoint } } ``` ### Health checks Add a `health_check` block inside an `endpoint` to tell Specific how to verify the service is healthy. The platform sends an HTTP `GET` to the given path on the endpoint's port; a `2xx` response means healthy. ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true health_check { path = "/healthz" } } env = { PORT = port } } ``` * `path` - the HTTP path to probe (required, must start with `/`). * Keep the handler cheap: don't query the database or call other services. A constant `200 OK` is sufficient. If your service already serves a root path that always returns `2xx` (for example, a static site), point `health_check` at `/`. * Only one `health_check` per service is used. If multiple endpoints declare one, the first one wins. * Background workers (services without endpoints) don't support `health_check` yet - only HTTP-serving endpoints do. In production, health checks control rollouts and restarts: * During a deploy, the new instance doesn't receive traffic until its health check passes. The old version stays up until then, so users never hit a half-started process. * If the health check starts failing after the deploy is live, the service is restarted automatically. Traffic is drained from the unhealthy instance before the restart. * If the health check never passes during a deploy (typically a misconfigured `path`), the deploy fails fast with a `health_check_failed` error pointing at the probe URL. ## Connecting services ### Private communication Services reference each other's endpoints with `private_url` to communicate over a private network: ```hcl specific.hcl theme={null} service "worker" { build = build.worker command = "./worker" env = { API_URL = service.api.private_url } } ``` Available service reference attributes: | Attribute | Description | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `service..private_url` | Internal URL without scheme (for example, `localhost:3001` in dev). Only reachable by other services. | | `service..host` | Host only. | | `service..port` | Port only. | | `service..public_url` | Public URL without scheme (`my-app.spcf.app` in production, `localhost:3001` in dev). Only available for endpoints with `public = true`. | For services with multiple named endpoints, specify the endpoint: `service.api.endpoint.main.private_url`. `public_url` and `private_url` do **not** include a scheme. Production services are served over HTTPS; local development uses plain HTTP. Compose the full URL with the right scheme per environment, using the `dev` block to override locally: ```hcl theme={null} env = { API_URL = "https://${service.api.public_url}" } dev { env = { API_URL = "http://${service.api.public_url}" } } ``` ### Public communication Private URLs aren't reachable from a browser. When a frontend needs to call a backend, the backend must expose a public endpoint, and the frontend references it with `public_url`: ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { PORT = port CORS_ORIGIN = "https://${service.web.public_url}" } dev { env = { CORS_ORIGIN = "http://${service.web.public_url}" } } } ``` ## Environment variables All connection details (database URLs, storage credentials, secrets) are injected as environment variables. The same references resolve to the correct values in both local development and production. ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { PORT = port NODE_ENV = "production" DATABASE_URL = postgres.main.url } } ``` ### String interpolation Embed references inside strings to compose values: ```hcl specific.hcl theme={null} service "worker" { build = build.worker command = "./worker" env = { QUERY_URL = "http://${service.api.private_url}/api/query" CUSTOM_DB = "host=${postgres.main.host} port=${postgres.main.port}" PUBLIC_API = "https://${service.api.public_url}/v1" } dev { env = { PUBLIC_API = "http://${service.api.public_url}/v1" } } } ``` All resource references (services, postgres, redis, storage, port, endpoint) can be used inside interpolated strings. Secret and config references cannot be interpolated; use them as standalone values. ## Local development ### Dev commands The `dev` block overrides how a service runs during `specific dev`. Use it for hot-reload servers, watch modes, or anything optimized for a fast feedback loop. If the referenced build has no `dev` block, the build step is skipped in development. ```hcl specific.hcl theme={null} service "web" { build = build.nextjs command = "npm start" endpoint { public = true } env = { PORT = port } dev { command = "npm run dev" # Handles building + serving with hot reload } } ``` The `dev.env` block is merged with the top-level `env`, so you only override the variables that differ. ### Dev-only services A service with a `dev.command` but no top-level `command` only runs in local development and is excluded from deployment. Useful for local versions of external services like mock servers: ```hcl specific.hcl theme={null} service "mock-api" { dev { command = "npx json-server --watch db.json --port $PORT" } endpoint {} env = { PORT = port } } ``` Dev-only services cannot have a `build` reference, and can define endpoints that other services reference during development. See [Local development](/concepts/local-development) for ports, logs, isolated instances, and tunnels. ## Monorepos Use `root` on builds to set the working directory. Services inherit the build's root, so commands like `npm start` run from the correct directory: ```hcl specific.hcl theme={null} build "backend" { base = "node" root = "packages/backend" command = "npm run build" } service "backend" { build = build.backend command = "node dist/index.js" dev { command = "npm run dev" } } ``` Dev-only services can set their own `root`. ## Workers Services without any endpoint act as background workers. They deploy like other services but don't receive HTTP traffic, which is common for queue consumers and background processing. ```hcl specific.hcl theme={null} service "worker" { build = build.worker command = "npm run worker" env = { DATABASE_URL = postgres.main.url } } ``` For work on a schedule, use [Crons](/guides/crons) instead. ## Pre-existing images Services can run a pre-built container image instead of a build. `image` and `build` are mutually exclusive, and image-based services skip the build step entirely: ```hcl specific.hcl theme={null} service "redis" { image = "redis:7" command = "redis-server --port $PORT" endpoint {} env = { PORT = port } dev { command = "redis-server --port $PORT" } } ``` * `image` - container image reference (for example, `redis:7` or `ghcr.io/org/image:tag`). * Use `dev.command` to run the equivalent process locally. * Deploy hooks work with image-based services, and you can mix build-based and image-based services in one project. ## Deploy hooks Run commands before or after deploying a service. Hooks run as one-off jobs with the same container and environment variables as the service. If a hook fails, the deployment is aborted. ```hcl specific.hcl theme={null} service "api" { build = build.api command = "node dist/index.js" endpoint { public = true } env = { PORT = port DATABASE_URL = postgres.main.url } pre_deploy { command = "npm run db:migrate" } post_deploy { command = "npm run cache:warm" } } postgres "main" {} ``` * `pre_deploy` - runs before the service is deployed. **Database migrations belong here**: the schema is updated before new code runs, and a failed migration aborts the deployment instead of leaving a broken state. * `post_deploy` - runs after the service is deployed (cache warming, notifications). In development, run migrations with [`specific exec`](/reference/cli#specific-exec) whenever the schema changes, for example `specific exec api -- npm run db:push`. ## Graceful shutdown When a service is redeployed or stopped, Specific sends your app a `SIGTERM` signal and waits a short grace period before forcibly stopping it. Handle `SIGTERM` to finish in-flight requests and close connections cleanly. For the signal to reach your code, `command` should run your app as a process that receives signals. Running your server directly (`node server.js`, `./api`) is the most reliable; wrappers and process managers can swallow the signal. ## Serving static files To serve static files, run a web server as a service. For example, with `npx serve`: ```hcl specific.hcl theme={null} build "spa" { base = "node" command = "npm run build" } service "frontend" { build = build.spa command = "npx serve dist -l $PORT" endpoint { public = true } env = { PORT = port } dev { command = "npm run dev" # Use your framework's dev server } } ``` ## Production Once deployed, stream logs, inspect metrics, and scale services from the [dashboard](https://dashboard.specific.dev). For querying logs and metrics from the CLI, see [Observability](/guides/observability). # Object storage Source: https://docs.specific.dev/guides/storage S3-compatible object storage that works with any S3 client. Managed S3-compatible object storage, powered by [Tigris](https://www.tigrisdata.com) in production. Works with any S3 SDK or tool. ```hcl specific.hcl theme={null} service "api" { build = build.api command = "./api" endpoint { public = true } env = { S3_ENDPOINT = storage.uploads.endpoint S3_ACCESS_KEY = storage.uploads.access_key S3_SECRET_KEY = storage.uploads.secret_key S3_BUCKET = storage.uploads.bucket } } storage "uploads" {} ``` You can declare multiple buckets; each `storage` block is its own bucket with its own credentials. ## Connection attributes | Attribute | Description | | ------------ | ------------------------------------------------------------------------- | | `endpoint` | S3-compatible endpoint URL (for example, `http://127.0.0.1:5000` in dev). | | `access_key` | Access key for authentication. | | `secret_key` | Secret key for authentication. | | `bucket` | Bucket name. | ## Example: AWS SDK (JavaScript) ```javascript theme={null} import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; const s3 = new S3Client({ endpoint: process.env.S3_ENDPOINT, region: "us-east-1", // Required but ignored locally credentials: { accessKeyId: process.env.S3_ACCESS_KEY, secretAccessKey: process.env.S3_SECRET_KEY, }, forcePathStyle: true, // Required for local S3-compatible servers }); await s3.send( new PutObjectCommand({ Bucket: process.env.S3_BUCKET, Key: "myfile.txt", Body: "Hello, world!", }) ); ``` ## Local development During `specific dev`, a local S3-compatible server runs automatically, and the same `storage.*` references resolve to it. Browse bucket contents from the [local dashboard](/concepts/dashboard#the-local-dashboard). ## Production Browse bucket contents and manage stored files from the [dashboard](https://dashboard.specific.dev). If a service outside of Specific needs to read from or write to a bucket, generate direct S3-compatible credentials (read/write or read-only) from the storage resource's **Access** tab in the dashboard. In [preview environments](/guides/previews), object storage is forked from the parent environment. # Real-time sync Source: https://docs.specific.dev/guides/sync Stream Postgres changes to clients over HTTP, powered by Electric. For Postgres databases, you can enable real-time data synchronization to build real-time and local-first applications. Sync is powered by [Electric](https://electric-sql.com), a sync engine that streams changes from Postgres to clients using a plain HTTP API. It uses a proxy-based architecture: your backend proxies requests to the sync engine after handling authentication and authorization. ## Enabling sync Reference `sync.url` and `sync.secret` on a Postgres database in your service env: ```hcl specific.hcl theme={null} postgres "main" {} service "api" { command = "node index.js" endpoint { public = true } env = { DATABASE_URL = postgres.main.url DATABASE_SYNC_URL = postgres.main.sync.url DATABASE_SYNC_SECRET = postgres.main.sync.secret } } ``` When these references are present, Specific automatically runs a sync engine connected to your Postgres database, locally during `specific dev` and managed in production. Sync attributes: | Attribute | Description | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `sync.url` | Sync engine HTTP endpoint URL (for example, `http://127.0.0.1:5133` in dev). | | `sync.secret` | Secret for authenticating requests to the sync engine. Pass it as the `secret` query parameter from your backend to the Electric API. | ## How sync works The sync engine streams "shapes" of data from Postgres to clients: 1. Your backend proxies shape requests to the sync engine (handling auth/authz). 2. The sync engine streams the initial data and subsequent changes. 3. Clients receive real-time updates over HTTP. For implementation details, see the Electric documentation: * [Authentication and proxying](https://electric-sql.com/docs/guides/auth) * [Shapes and client usage](https://electric-sql.com/docs/guides/shapes) * [Handling writes](https://electric-sql.com/docs/guides/writes) * [Troubleshooting](https://electric-sql.com/docs/guides/troubleshooting) ## Proxy configuration When proxying Electric requests from your backend, handle headers and query parameters carefully. Getting these wrong causes silent failures: browsers block responses or serve stale cached data without clear error messages. ### Expose Electric response headers Electric returns custom `electric-*` headers that the client SDK needs to follow the shape log. Browsers block JavaScript from reading non-standard response headers unless they are listed in `Access-Control-Expose-Headers`. Don't strip any `electric-*` headers from the response, and expose them all: ``` Access-Control-Expose-Headers: electric-handle, electric-offset, electric-schema, electric-cursor, electric-up-to-date, electric-chunk-last-offset ``` ### Strip upstream headers Electric's response includes its own CORS and caching headers. If your proxy copies these through and your CORS middleware also adds its own, the browser receives duplicate `Access-Control-Allow-Origin` values and rejects the response. Before setting your own headers, strip these from Electric's response: * `Access-Control-Allow-Origin` and other `Access-Control-*` headers * `Content-Encoding` and `Content-Length` (fetch decompresses the body but doesn't update these headers, which breaks browser decoding) * `Cache-Control` (see below) ### Override caching Electric returns `Cache-Control` with `max-age` and `stale-age` for request collapsing at the CDN level. During development, this can cause browsers to serve stale cached responses. For example, responses cached before CORS headers were configured correctly keep failing even after the proxy is fixed. Override with `Cache-Control: no-store` on your proxy response. ### Control query parameters Set these server-side and never pass them through from the client: * `table` - letting clients specify the table allows access to any table * `where` - this is your authorization filter * `columns` - clients could request sensitive columns * `secret` - never expose the API secret to clients Only forward Electric protocol parameters from the client: `offset`, `handle`, `live`, `live_sse`, `cursor`, `expired_handle`, `replica`, `log`. ## Using the Electric TypeScript SDK `ShapeStream` requires a full URL, not a relative one. In browsers, derive it from `window.location.origin`: ```typescript theme={null} import { ShapeStream } from "@electric-sql/client"; const stream = new ShapeStream({ url: `${window.location.origin}/api/sync/items`, }); ``` This works correctly regardless of the deployment environment. # Temporal Source: https://docs.specific.dev/guides/temporal Managed Temporal workflow engines for durable workflows and background tasks. Define managed [Temporal](https://temporal.io) workflow engines for durable workflows, background tasks, AI agents, batch jobs, and more. To simply run a command on a schedule, prefer the built-in [`cron`](/guides/crons) block. Each run is a one-off job, so there's no persistent worker to keep running. Reach for Temporal's own schedule support when you need complex or long-running scheduled workflows (durable, multi-step, with retries), or when you already run a Temporal worker. Temporal has SDKs for TypeScript, Python, Go, Java, .NET, and PHP. See the [Temporal documentation](https://docs.temporal.io/) for language-specific guides on workers, workflows, and activities. This page covers the Specific integration. ## Configuration Define a `temporal` block and reference it from services: ```hcl specific.hcl theme={null} temporal "tasks" {} build "app" { base = "node" } service "worker" { build = build.app command = "node worker.js" env = { TEMPORAL_ADDRESS = temporal.tasks.url TEMPORAL_NAMESPACE = temporal.tasks.namespace TEMPORAL_API_KEY = temporal.tasks.api_key } dev { command = "node --watch worker.js" } } ``` ## Reference attributes | Attribute | Description | Dev value | Production value | | --------------------------- | ----------------------------------- | ---------------------------- | --------------------------- | | `temporal..url` | gRPC address of the Temporal server | `localhost:` | Temporal Cloud gRPC address | | `temporal..namespace` | Temporal namespace | `default` | Managed namespace ID | | `temporal..api_key` | API key for authentication | `""` (empty, no auth in dev) | Auto-generated API key | These can be used in service `env` blocks, both standalone and inside interpolated strings. ## Local development Running `specific dev` automatically: 1. Downloads the Temporal CLI (first run only). 2. Starts a Temporal dev server with persistent storage. 3. Makes the Temporal Web UI available in the [local dashboard](/concepts/dashboard#the-local-dashboard) sidebar under **Workflows**. Workflow data persists across dev server restarts in a SQLite database under `.specific/keys//data/`. The `api_key` attribute is an empty string in dev since the Temporal dev server doesn't require authentication. This is safe: Temporal SDKs apply authentication only when a non-empty key is provided. ## Production Running `specific deploy` automatically provisions a managed [Temporal Cloud](https://temporal.io/cloud) namespace for each `temporal` block, with no manual setup: 1. A dedicated Temporal Cloud namespace is created. 2. A service account with write access is provisioned. 3. An API key is generated for authentication. 4. Credentials are securely injected into your services. The same references resolve to the Temporal Cloud values in production, so no environment-specific overrides are needed. # Volumes Source: https://docs.specific.dev/guides/volumes Persistent directories that survive deploys and restarts. Volumes provide a directory that persists across deployments and restarts, useful for file uploads, caches, and other data that needs to survive. Volumes are defined as sub-blocks within a service. Each volume has a name and exposes a `path` attribute that resolves to the directory path: ```hcl specific.hcl theme={null} service "api" { build = build.api command = "node server.js" volume "uploads" {} env = { UPLOADS_DIR = volume.uploads.path } } ``` ## Attributes | Attribute | Description | | --------- | -------------------------------------- | | `path` | Absolute path to the volume directory. | ## How it works * **In production**: each volume is backed by a persistent disk, and `path` resolves to `/volumes/{name}` inside the container. * **In development** (`specific dev`): each volume maps to a local directory at `.specific/keys/.../data/volumes/{service}/{name}/`. Volume data persists across deployments and dev server restarts. ## Multiple volumes A service can define multiple volumes: ```hcl specific.hcl theme={null} service "api" { build = build.api command = "node server.js" volume "uploads" {} volume "cache" {} env = { UPLOADS_DIR = volume.uploads.path CACHE_DIR = volume.cache.path } } ``` ## Example usage (Node.js) ```javascript theme={null} import fs from "fs"; import path from "path"; const uploadsDir = process.env.UPLOADS_DIR; // Write a file fs.writeFileSync(path.join(uploadsDir, "myfile.txt"), "Hello, world!"); // Read it back (persists across restarts) const content = fs.readFileSync(path.join(uploadsDir, "myfile.txt"), "utf8"); ``` ## Preview environments [Preview environments](/guides/previews) get an instant copy-on-write clone of each volume, so a preview's service starts on an exact copy of the parent's data with no extra configuration, and writes to the clone never affect the parent. # Welcome Source: https://docs.specific.dev/index Specific enables any coding agent to define infrastructure for the code it writes. This lets you start building locally and deploy to production in minutes. Specific can be used with any programming language or framework, and doesn't require integrating any SDKs. Simply connect your preferred coding agent and build whatever you can dream up. Your coding agent will define the infrastructure it needs from us and write code to integrate with it. Hand setup to your agent with one prompt, or clone an example project Install Specific for your own project and get started building Connect Claude Code, Cursor, or Codex and let it build with Specific The mental model: one config file, every environment ### Building with Specific As you are building, a development environment is automatically created for your app, providing the best possible environment for rapid iteration. When you are happy with what you've built, you can deploy to production with a single command to our secure and scalable infrastructure. Specific provides all the building blocks your coding agent needs to build anything: * **[Frontend and backend services](/guides/services)** with support for any programming language and framework * **[Postgres databases](/guides/postgres)** with zero-downtime migrations and automatic scaling * **[Real-time sync](/guides/sync)** to build collaborative applications directly from Postgres * **[Object storage](/guides/storage)** for files and media with infinite scaling * **[Crons](/guides/crons)**, **[durable workflows](/guides/temporal)**, **[caches](/guides/redis)**, and **[volumes](/guides/volumes)** * **[Secrets management](/guides/secrets-and-config)** with secure storage and injection into your services * **[Preview environments](/guides/previews)** and **[SQL-queryable observability](/guides/observability)** once deployed Best of all, Specific is completely free for local development and dead simple to get started with. # Installation Source: https://docs.specific.dev/installation Install the Specific CLI and prepare your project. Specific is a single CLI that runs your local development environment, handles deployments to Specific Cloud, validates your configuration, and serves documentation to your coding agent. ## Install the CLI Specific supports macOS, Linux, and Windows (via WSL). ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` This detects your platform, downloads the latest binary, and adds it to your `PATH`. Download the latest binary for your platform: ```bash theme={null} # macOS (Apple Silicon) curl -fsSL "https://binaries.specific.dev/cli/$(curl -s https://binaries.specific.dev/cli/latest)/specific-darwin-arm64" -o specific # macOS (Intel) curl -fsSL "https://binaries.specific.dev/cli/$(curl -s https://binaries.specific.dev/cli/latest)/specific-darwin-x64" -o specific # Linux (x86_64) curl -fsSL "https://binaries.specific.dev/cli/$(curl -s https://binaries.specific.dev/cli/latest)/specific-linux-x64" -o specific # Linux (ARM64) curl -fsSL "https://binaries.specific.dev/cli/$(curl -s https://binaries.specific.dev/cli/latest)/specific-linux-arm64" -o specific ``` Then make it executable and move it somewhere on your `PATH`: ```bash theme={null} chmod +x specific mv specific ~/.local/bin/ ``` Verify the installation: ```bash theme={null} specific --version ``` The CLI keeps itself up to date automatically; run `specific update` to update on demand. ## Set up your project Inside your project folder, run: ```bash theme={null} specific init ``` This adds Specific instructions to your coding agent's configuration (`CLAUDE.md`, `AGENTS.md`, or Cursor rules, auto-detected) and gitignores Specific's local files. See [Coding agents](/coding-agents) for details. ## Next steps Clone an example and go from dev to deployed in five minutes. The mental model behind specific.hcl. # Quickstart Source: https://docs.specific.dev/quickstart Let your agent set everything up, or go from local dev to deployed yourself in about five minutes. ## Let your agent do it The fastest way to get started is to hand the setup to your coding agent. Paste this prompt into Claude Code, Cursor, Codex, or whichever agent you use: ```text wrap theme={null} Help me get started with Specific by following: https://docs.specific.dev/for-ai/onboarding ```
Your agent installs the CLI, sets up a project (yours or an example), runs it locally, and walks you through deploying, explaining each step along the way. ## Or do it yourself Prefer to run the commands yourself? In this quickstart you clone a small real-time app, run it locally with one command, and deploy it to production with another. ```bash theme={null} curl -fsSL https://specific.dev/install.sh | sh ``` Together with Claude Code, we have created a minimal example to get you familiar with Specific; a click counter with database persistence and realtime sync. ```bash lines theme={null} git clone https://github.com/specific-dev/examples.git cd examples/node-realtime-click-counter npm install ``` Now start the dev server: ```bash theme={null} specific dev ``` This spins up the web app and any dependencies (Postgres, sync engine, etc.) locally with everything connected automatically. The database schema is also automatically applied. The terminal output includes the URLs: * The [local dashboard](/concepts/dashboard#the-local-dashboard) (usually [http://localhost:3000](http://localhost:3000)) visualizes your architecture and lets you manage your data. * The app itself (usually [http://localhost:3001](http://localhost:3001)). Open it in two browser windows and click: the count syncs in real time. Deploying to Specific Cloud requires an account. The command will automatically prompt you to log in. ```bash theme={null} specific deploy ``` After deploying, you will get your very own production server up and running in the cloud. To observe and manage your app, visit the [Specific Dashboard](https://dashboard.specific.dev). Now you can run the following command to give your agent of choice (e.g. Claude Code, Cursor, Codex, etc.) the knowledge it needs to build with Specific: ```bash theme={null} specific init ``` From now on, your agent should have the context it needs. To verify that this is the case, ask your agent `What is Specific?` and the answer should be clear. Now try passing it the following prompt: ```text wrap theme={null} Add the ability for users to upload a custom background image to S3. When the background changes, it should be synced in real-time to all connected clients. ``` Your agent should understand that it can use Specific's S3-compatible object storage and proceed with implementing it. ## Next steps How agents work with Specific: init, bundled docs, and skills. The mental model behind specific.hcl. Define how your code runs and connects. Managed databases with zero-downtime migrations. # CLI reference Source: https://docs.specific.dev/reference/cli Every command in the Specific CLI, grouped by workflow. The `specific` CLI is the primary interface to Specific, for humans and coding agents alike. Run `specific --help` or `specific --help` for built-in help. ## Setup ### specific init Prepare a project for use with a coding agent. Writes Specific usage instructions into your agent's configuration file (`CLAUDE.md` for Claude Code, `AGENTS.md` for Codex, `.cursor/rules/specific.mdc` for Cursor) and adds `.specific` and `specific.local` to `.gitignore`. ```bash theme={null} specific init ``` | Option | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------- | | `--agent ` | Agents to configure: `cursor`, `claude`, `codex`, `other`. Auto-detected from existing config files if omitted. | ```bash theme={null} # Configure for Claude Code and Cursor specific init --agent claude cursor ``` ### specific docs Fetch LLM-optimized documentation bundled with the CLI. Without a topic, prints the documentation index. Topics are nested paths. ```bash theme={null} specific docs specific docs services specific docs postgres/reshape ``` ### specific check Validate the `specific.hcl` configuration file. Lists all builds, services, databases, storage, redis, and configs defined in the file, and reports errors for invalid configurations, including Reshape migration validation. ```bash theme={null} specific check ``` Exits with code 1 if there are any errors. Run it after every change to `specific.hcl` or your migration files. ## Local development ### specific dev Start the local development environment. Reads `specific.hcl` and starts all resources and services on local ports, printing their URLs. The local dashboard is usually at `http://localhost:3000`, with services on the ports next to it. ```bash theme={null} specific dev ``` | Option | Description | | ----------------- | ------------------------------------------------------------------------------------------------ | | `-k, --key ` | Run an isolated dev environment with separate data and ports. Auto-detected from git worktrees. | | `--tunnel` | Expose public services via `*.tunnel.spcf.app` URLs so others (or remote agents) can reach them. | ```bash theme={null} # Start an isolated environment for a feature branch specific dev --key feature-auth # Expose services publicly via tunnel specific dev --tunnel ``` ### specific exec Run a one-off command with a service's environment variables and its dependencies started. If `specific dev` is already running, `exec` reuses the existing resources. Otherwise, it starts the required resources temporarily and stops them when the command finishes. This is the primary way to run database migrations, seed scripts, and other setup commands. ```bash theme={null} specific exec -- ``` | Option | Description | | ----------------- | ---------------------------------------------------------------------------- | | `-k, --key ` | Dev environment namespace. Auto-detected from git worktrees. | | `--cwd ` | Override the working directory (defaults to `service.root` or `build.root`). | ```bash theme={null} # Run database migrations specific exec api -- npm run db:migrate # Run a cron's own command specific exec my-cron # Run from the repository root instead of the service root specific exec --cwd . api -- npx expo start ``` The `--` separator distinguishes the service arguments from the command to execute. Running `specific exec ` without a command runs the cron's configured command. ### specific psql Connect to a local Postgres database with an interactive `psql` session. If the database is not running, it is started automatically. When only one database is defined in `specific.hcl`, the database name is optional. ```bash theme={null} specific psql [database] ``` | Option | Description | | ----------------- | ------------------------------------------------------------ | | `-k, --key ` | Dev environment namespace. Auto-detected from git worktrees. | ```bash theme={null} # Run a single query specific psql main -- -c "SELECT * FROM users LIMIT 5" # List all tables specific psql main -- -c "\dt" ``` Extra arguments after `--` are passed directly to `psql`. For production databases, use [`specific query --db`](#specific-query) instead. ### specific reshape Manage [Reshape](/guides/reshape) zero-downtime migrations manually. During `specific dev`, migrations are managed automatically; these commands are for manual control. ```bash theme={null} specific reshape [database] ``` | Option | Description | | ----------------- | ------------------------------------------------------------ | | `-k, --key ` | Dev environment namespace. Auto-detected from git worktrees. | ```bash theme={null} specific reshape status specific reshape complete mydb ``` `check` validates migration file syntax and works without a running database; the other actions need one (started automatically if `specific dev` isn't running). ### specific clean Remove local development data. Deletes the resource data stored in `.specific/keys/`, giving you a fresh start with empty databases and storage. Cannot be run while `specific dev` is active. ```bash theme={null} specific clean ``` | Option | Description | | ----------------- | ------------------------------------------------------- | | `-k, --key ` | Remove data only for the specified dev environment key. | ## Deploy and manage ### specific deploy Deploy the project to Specific Cloud. On first deploy, prompts you to log in and create or select a project; afterwards the project is remembered in `.specific/project.json`. ```bash theme={null} specific deploy ``` | Option | Description | | ------------------------------ | --------------------------------------------------------------- | | `--project ` | Project ID to deploy to (overrides the saved project). | | `-e, --environment ` | Target environment. Auto-selected if only one exists. | | `--secret ` | Secret values (repeatable). | | `--config ` | Config values (repeatable). | | `--preview` | Deploy to an ephemeral [preview environment](/guides/previews). | ```bash theme={null} specific deploy --environment staging specific deploy --preview specific deploy --secret db_url=postgres://... --config domain=app.com ``` ### specific status Show the current project, its environments (including preview environments and their `env_...` IDs), and deployment status. ```bash theme={null} specific status ``` ### specific query Run a SQL query against your environment's [observability data](/guides/observability) (ClickHouse), or against a production Postgres database with `--db` (read-only). ```bash theme={null} specific query "SELECT count() FROM observability.logs" ``` | Option | Description | | ------------------------------------ | ---------------------------------------------------------------------------------------------- | | `-e, --environment ` | Target environment (defaults to the current one). | | `--db ` | Query a Postgres database by name with Postgres SQL (read-only) instead of observability data. | | `--format ` | Output format. Defaults to `table` on a TTY, `jsonl` when piped. | ```bash theme={null} specific query --environment staging "SELECT * FROM observability.logs LIMIT 5" specific query --db main "SELECT * FROM users LIMIT 5" # Read the query from stdin cat queries/p99.sql | specific query ``` ### specific domain Manage custom domains for deployed services. `add` registers a domain and prints the DNS records you need to create. Removing a domain is done in the [dashboard](https://dashboard.specific.dev). ```bash theme={null} specific domain add ``` | Option | Description | | ------------------------------ | ------------------------------------------------- | | `-e, --environment ` | Target environment (defaults to the current one). | ```bash theme={null} specific domain add web api.example.com specific domain add web example.com --environment staging ``` ### specific project Manage projects. ```bash theme={null} specific project new specific project list ``` | Option | Description | | ------------ | ----------------------------------------------------------------------------- | | `--org ` | Organization ID for `new` (required if you belong to multiple organizations). | ## Account ### specific login Log in to Specific. Opens a browser for authentication; in non-interactive environments it prints a device-authorization link and code instead. ```bash theme={null} specific login ``` | Option | Description | | ---------------------- | ------------------------------------------------------------------------- | | `--device-code ` | Complete login using a device code from a previous non-interactive login. | ### specific logout Log out of Specific. ```bash theme={null} specific logout ``` ### specific update Update the Specific CLI to the latest version. The CLI also auto-updates in the background. ```bash theme={null} specific update ``` ### specific beta Manage beta feature flags interactively. ```bash theme={null} specific beta ``` # Why Specific? Source: https://docs.specific.dev/why-specific The case for agent-first infrastructure. Coding agents are rapidly improving and writing more code. But when it comes to infrastructure, they hit a wall. To understand what's deployed, they'd need to navigate CLI output. Terraform solves declaration by defining infrastructure as code, but it doesn't handle local dev or deployment. Docker Compose handles local dev, but production requires separate tooling that must be kept in sync. The result is that agents can write your code, but the path from code to running application remains fragmented and manual. Specific closes that gap: your agent declares services, databases, storage, and more in a single configuration file that lives next to your code, and the CLI runs the whole stack locally and deploys it to production. See [How Specific works](/concepts/how-it-works) for the mental model. ## Built for the agent feedback loop After a successful deployment, anything that can fail will fail. Specific is designed so your agent can find out what went wrong without a human relaying screenshots: * `specific check` validates every configuration change before it's applied. * `specific dev` runs the full stack locally, with per-service log files the agent can read and grep. * `specific query` gives the agent SQL access to production [logs and metrics](/guides/observability), scoped to an environment. The agent that wrote the change is the one debugging it, with direct access to the evidence. ## Not a coding agent Specific works with the coding agent you already use, like Claude Code, Codex, or Cursor. The CLI gives your agent the documentation, validation, local environment, and deployment commands it needs to change infrastructure safely alongside your application code. See [Coding agents](/coding-agents) for how that's wired up. ## No SDKs, no lock-in Your application never imports a Specific library. Everything arrives through environment variables and standard protocols: Postgres is Postgres, storage is S3-compatible, Redis is Redis-compatible. That has practical consequences: * Any language and framework works, and a custom Dockerfile covers custom runtimes. * Services Specific doesn't provide still work: connect to external APIs, hosted services, or third-party databases through normal secrets and client libraries. * Authentication stays yours. Use Better Auth, WorkOS, Clerk, or your own; Specific handles infrastructure and stays out of your user model. ## Agents with guardrails Letting an agent touch infrastructure raises a fair question: what stops it from breaking things? * Infrastructure changes are written to `specific.hcl`, so they're reviewed like code and validated with `specific check`. * Agents work through Specific's config schema and CLI, not arbitrary cloud or account settings. * The full stack is testable locally before anything ships, and `specific deploy` runs build checks before provisioning or rolling out. * Destructive actions and production controls, like scaling, changing production secrets, and deleting projects, stay with humans in the [dashboard](/concepts/dashboard). Humans also configure deployment policy, like GitHub deploys and automatic PR previews. ## How Specific compares Declaration is where Terraform stops; Specific covers dev, deploys, and operations. Standard tools and any backend stack instead of an SDK-locked backend. No proprietary runtime or SDK; plain Postgres and normal protocols. Full-stack infrastructure, not just frontend hosting.