You ship faster when your backend behaves the same on your laptop as it does in production. With the Nhost CLI, you can spin up a complete, production-parity backend locally in containers: Postgres, real-time GraphQL, Authentication, Storage, and Serverless Functions. Then add your own language runtimes alongside using Bring your own containers for true end-to-end parity. This is local development with CLI that actually matches what you deploy, without writing Docker by hand or guessing at environment drift.
Why local dev with the Nhost CLI
Local development with CLI should be a one-command experience. The Nhost CLI gives you exactly that, backed by Docker Compose under the hood for predictable, reproducible environments. You get:
- Production parity by default: The same Postgres database, GraphQL API, Authentication, Storage, and Functions you run in the cloud are orchestrated locally with the same contracts and JWT rules.
- Faster feedback loops: Start your stack in seconds, see printed service URLs, iterate on functions with hot reload, and validate permissions in the GraphQL console without context switching.
- No DevOps tax: Skip writing and maintaining custom Compose files for core services. The Nhost CLI wires essentials for you, while keeping extension points open.
- Bring your own containers (BYOC): Run any language or runtime beside the Nhost stack locally, then promote the same container to the cloud with identical networking, env, and auth contracts.
- Team-friendly workflows: Database migrations and metadata live in Git, so new teammates can clone, start, and be productive fast.
Prerequisites and install
Before you begin, confirm a few basics:
- Docker and Docker Compose: The engine and Compose v2 power all containers. This ensures parity across macOS, Windows, and Linux.
- Nhost CLI: Install the CLI to scaffold projects, manage services, apply migrations, and interact with the local stack.
- Optional cloud link: Log in via the CLI to associate your local project with an Nhost cloud project if you want to sync settings or later deploy with CI/CD.
- Git: Your database migrations, Hasura metadata, and other config are tracked in version control for safe, collaborative changes.
With these pieces in place, local development with CLI becomes a single command that starts your backend and any custom services side-by-side.
Project scaffold and layout
When you create or connect a project, the repository structure clearly maps to how the Nhost platform operates in production:
- Database migrations: A folder that holds SQL migrations and seed data. Every schema change is reproducible and reviewable in Git.
- Hasura metadata: Sources, tracked tables, relationships, role-based permissions, Actions, and Remote Schemas are captured here. This is the source of truth for your GraphQL API.
- Functions: A directory for TypeScript or JavaScript serverless functions with entry points, tests, and local dev hooks.
- Auth configuration: Environment-based settings for JWTs, providers, and security policies. These are consistent across local and cloud.
- Storage artifacts: A mapping for local S3-compatible storage to exercise uploads, downloads, and signed URLs.
- Optional services: A services folder for Bring your own containers with a Dockerfile per service and any compose overrides you maintain.
- Environment files: Templates for env and secrets that your team can copy locally without exposing credentials in Git.
This layout keeps Postgres schemas, GraphQL metadata, Authentication rules, and Functions changes synchronized. Docker Compose orchestrates the containers, while the Nhost CLI manages lifecycle and consistency.
Start the stack locally
Starting the full stack with the Nhost CLI launches containers for:
- Postgres: An enterprise-grade SQL engine with a persistent Docker volume so your data and extensions survive restarts.
- GraphQL API: Real-time GraphQL on top of your database with live queries, subscriptions, and permission checks tied to JWT claims.
- Authentication: Secure sign-up, sign-in, and user management with email/password and optional providers.
- Storage: S3-compatible file storage for uploads/downloads and testing signed URLs.
- Serverless Functions: JS/TS functions that hot reload during local development for tight iteration loops.
The CLI prints URLs for each service: the GraphQL console, the authentication endpoints, the storage admin, and function invocation routes. Functions update as you save files, and Postgres persists state in volumes so you can stop and resume without losing your database.
Data and GraphQL in containers
With containers running, apply database migrations and metadata from Git to reproduce your schema, tables, relationships, and role-based policies. Open the local GraphQL console to inspect tracked tables, run queries and mutations, and subscribe to changes in real time. This is where you validate that column-level and row-level permissions are enforced as expected.
Because the GraphQL API reads JWTs issued by Nhost Authentication, every operation is checked against the same roles and claims you use in production. If a query works locally with your current role, you can be confident it will behave identically in the cloud environment.
Authentication end-to-end
Configure local sign-up and sign-in flows using email and password, magic links, or provider-based auth depending on your project needs. Test JWT-based access across the GraphQL API and verify claims such as default_role and allowed_roles. For repeatable setups, seed or import a set of demo users so your team and CI pipelines run against consistent identities and roles.
If you are building AI agents or external clients that must call your backend securely, see the detailed flow in How to Add OAuth2 and JWT Authentication to Your AI Agents (Step-by-Step Guide). The same JWT patterns apply locally and in production, which simplifies testing and reduces integration bugs.
Storage and file handling
Local storage runs with an S3-compatible service so you can test uploads, downloads, and signed URL lifecycles. Exercise flows such as:
- Uploading a profile image and validating access control by role or ownership.
- Generating short-lived signed URLs for client-side downloads and ensuring they expire as configured.
- Verifying MIME type validation, file size limits, and folder conventions before pushing to production.
Because local storage mirrors the CDN-backed storage in Nhost cloud, behavior you validate here carries forward without surprises.
Serverless functions
Use the Functions directory to implement business logic, webhooks, rate-limited endpoints, and simple back-office tasks. During local development with CLI, changes hot reload so you can iterate rapidly. Manage environment variables for secrets and configuration, and wire functions to:
- Hasura Actions: Extend GraphQL with custom queries or mutations that call your function and return typed results.
- Event Triggers: React to database changes with predictable at-least-once semantics.
- Scheduled tasks: Run periodic jobs without servers, verified locally before enabling in production.
Bring Your Own Containers (BYOC) overview
Some features require a custom runtime or specialized dependencies: Python for ML inference, Go for high-throughput services, or Rust for performance-sensitive tasks. Bring your own containers integrates any language or framework as a first-class service. Locally, the Nhost CLI and Docker Compose manage lifecycle and networking so your custom service can talk to Postgres, Authentication, Storage, and the GraphQL API. In the cloud, you deploy the same container with the same contract for zero-drift promotion.
Scaffold your service
Add a new directory under services with a Dockerfile that builds your runtime, installs dependencies, and sets a startup command. Pick a container port for liveness and readiness checks, and define a lightweight health endpoint. Having a healthcheck ensures Compose orchestrates clean start order and the Nhost CLI reports readiness accurately during local development with CLI.
Wire into Docker Compose
Register your service via a compose override that the Nhost CLI automatically picks up. Attach it to the Nhost network so service discovery is consistent, and provide environment variables and secrets using the same pattern as your core services. This lets you consume the GraphQL endpoint, Postgres connection strings, and Authentication endpoints from your BYOC runtime without hardcoding anything. Using Docker Compose here keeps configuration minimal and portable.
Connect to GraphQL
Expose your service to the GraphQL API using Hasura Actions or Remote Schemas. Forward the Nhost JWT from the incoming request, verify claims inside your custom runtime, and enforce the same role-based access control you have in metadata. This approach keeps authorization consistent across native resolvers and custom business logic. For a deeper look at JWT flows that are easy to replicate in your service, consult How to Add OAuth2 and JWT Authentication to Your AI Agents (Step-by-Step Guide).
Dev loop and DX tips
- Rebuild quickly: Rebuild or restart a single BYOC service without touching Postgres or GraphQL to shorten feedback loops.
- Tail logs: Use the CLI to follow aggregated logs across services and pinpoint cross-service issues faster.
- Hot reload: Where your runtime supports it, mount sources for hot reload to keep iteration fast.
- Profile latency: Measure round-trip time between your GraphQL Actions and BYOC endpoints to catch N+1 patterns and tune timeouts early.
Debugging and observability
When something feels off, lean on built-in tools:
- CLI logs and health status: Confirm container readiness, restarts, and errors. Healthchecks surface dependency issues early.
- GraphQL console: Inspect permissions, generated SQL, and response headers. Validate that headers include the expected roles and auth claims.
- Database shell: Connect to Postgres locally to explain analyze slow queries, check indexes, and validate RLS policies directly.
- Auth event trails: Review sign-in/sign-up flows and token issuance to isolate permission mismatches.
- Storage behavior: Try uploading and downloading with different roles to ensure policies match expectations.
Testing and CI parity
The same Docker Compose definitions that power your laptop can run headlessly in CI for integration and end-to-end tests. Recommended practices:
- Deterministic seeds: Load baseline migrations, metadata, and seed data so tests run against a known-good state.
- Ephemeral environments: Spin the stack up per test job, run suites, and tear down to keep tests isolated.
- Stable URLs: Use the same service hostnames and ports locally and in CI so clients do not need environment-specific rewrites.
- JWT fixtures: Generate or store short-lived tokens for roles under test to verify GraphQL permissions and BYOC endpoints consistently.
This approach ensures that what you validate in automation is what you will experience in production, from schema and metadata to Authentication and custom services.
From local to cloud
Promoting changes is straightforward because Nhost is designed around Git and container images:
- Commit migrations and metadata: Open a PR for your database and GraphQL changes. Code review catches breaking permission changes or schema regressions before deploy.
- CI/CD and Git deployments: Merge to your main branch to trigger a deployment in Nhost cloud that applies the exact migrations and metadata you tested locally.
- Publish BYOC images: Build and push your BYOC container to a registry. Reference this tag in your Nhost project so the platform pulls the same artifact you ran locally.
- Map env and secrets: Use the Nhost dashboard or Git-based config to provide environment variables consistently across local and cloud.
- Endpoint and JWT continuity: Your GraphQL URLs, auth headers, and JWT claim formats do not change, reducing the risk of deployment-only bugs.
Common pitfalls and fixes
- Port conflicts: If a local port is already taken, update your compose override to remap host ports while keeping container ports unchanged for service discovery.
- Stale volumes: When schemas change drastically, clear or reseed Docker volumes to avoid inconsistent database states. Keep seeds small and targeted.
- JWT or env drift: Ensure your BYOC service reads the same env variable names locally and in cloud. Mismatched secrets or issuer/audience values cause silent authorization failures.
- Out-of-sync metadata: If the GraphQL console differs from expected permissions, reapply metadata from Git and confirm role policies are correct.
- Compose cache: When dependencies update, force a clean rebuild of BYOC images to avoid running stale layers.
Wrap-up and next steps
With the Nhost CLI orchestrating Postgres, GraphQL, Authentication, Storage, and Functions, you get local development with CLI that matches production from the first keystroke. Add Bring your own containers to run any language beside your core services, then ship the same containers to the cloud with identical JWT enforcement, networking, and environment configuration. This removes the guesswork from integration and puts your focus back on product delivery.
Spin up your first project, add a simple BYOC service, and run your end-to-end flows today. Get started for free.
Frequently Asked Questions
How do BYOC services discover and securely call Nhost GraphQL/Auth locally and in the cloud?
Attach your service to the Nhost network so hostnames for GraphQL and Authentication resolve consistently. Read the endpoints and secrets from environment variables rather than hardcoding them. Forward the incoming Nhost JWT from clients to your service and validate claims before calling downstream GraphQL operations. The same contract applies in cloud, so you can promote without rewriting URLs or auth logic.
Can I run the Nhost CLI without Docker Desktop (e.g., Linux with Docker Engine + Compose v2)?
Yes. The Nhost CLI relies on Docker Engine and Docker Compose, not on a specific desktop distribution. On Linux, install the engine and Compose v2, then start the stack as usual. Service networking, volumes, and healthchecks work the same way across platforms.
What’s the recommended way to persist or reset local data and files between runs?
Database and storage use persistent Docker volumes so your state survives restarts. To reset, stop services and prune the relevant volumes to return to a clean slate, then reapply migrations, metadata, and seed files. Keep seed data small and deterministic so teammates and CI runs produce identical states.
How do I share a reproducible local setup with my team (env, migrations, services) without leaking secrets?
Commit migrations, metadata, function code, and compose overrides to Git. Provide environment templates (example files) that teammates can copy and fill locally. Store actual secrets outside version control: in your local secret manager, CI provider, or the Nhost dashboard for cloud. This keeps environments consistent without exposing credentials.
How do I validate and pass Nhost JWTs from Hasura to my BYOC service and enforce role-based access?
When you define a Hasura Action or Remote Schema, configure it to forward the Authorization header to your BYOC endpoint. In your service, verify the token with the same issuer, audience, and signing key used by Nhost Authentication, then enforce roles and claims before executing logic. This ensures the same permission model applies across native resolvers and custom endpoints.
💬 Contact Us
Have a question or want to learn more? Send us a message!