---
title: Config as code
description: Keep a service's settings in dekka.toml or dekka.json next to its code, and describe a whole environment in a dekka.yaml blueprint.
section: Services
order: 5
---

A `dekka.toml` or `dekka.json` in a service's root directory sets its build and runtime settings from the repository. Dekka reads the file from the commit being deployed, so a settings change can go through code review with the code that needs it.

## Write a config file

The file has two sections, `build` and `runtime`, and accepts the names listed in [Build and deploy settings](/docs/build-configuration#setting-names-in-the-api-and-config-files) without their prefix.

```toml title="dekka.toml"
[build]
build_command = "pip install -r requirements.txt"
start_command = "uvicorn main:app --host 0.0.0.0 --port $PORT"
pre_deploy_command = "alembic upgrade head"
watch_paths = ["api/**"]

[runtime]
health_check_path = "/healthz"
memory_mib = 512
```

The same settings in JSON look like this, and a `$schema` key is ignored if you add one for your editor.

```json title="dekka.json"
{
  "build": { "pre_deploy_command": "python manage.py migrate --noinput" },
  "runtime": { "health_check_path": "/health/", "port": 8000 }
}
```

## Which value wins?

A setting in the file overrides the same setting in the service's dashboard settings, for every deployment of a commit that contains the file. Settings the file leaves out keep their dashboard values, and settings set in neither place use their defaults. Removing a line from the file hands that setting back to the dashboard on the next deploy.

The file only applies to services deployed from GitHub. An image service has no repository to read it from.

## See where a deployment's settings came from

In [Deployments](/docs/deployments), a deployment that used a config file shows a line such as "3 settings came from dekka.toml in the repository", which opens to list each setting. The API returns the same information for every setting in `config_sources`, with one of `dekka.toml`, `dekka.json`, `service settings` or `default`, and the merged result in `effective_spec`.

## What if the file is wrong?

Dekka checks the file before anything is built, and an unknown section or setting, a value out of range or a file it can't parse fails the deployment with `invalid_config` and a message naming the problem, such as `dekka.toml is invalid: runtime.memory_mib Input should be less than or equal to 16384.` The release that is serving keeps serving.

A few other cases fail the same way. A root directory can hold only one of the two files, and a file can't change how a service runs, so a `cron_schedule` in a web service's file is an error. A value over your plan's limit, such as `replicas = 4` on Starter, fails the deployment with `entitlement_exceeded`.

## Describe a whole environment in dekka.yaml

A `dekka.yaml` blueprint describes an environment's services, databases, buckets, variables and connections in one file. Choose **Add**, then **Template or dekka.yaml**, and either pick one of Dekka's templates, such as **Next.js with Postgres** or **FastAPI with Postgres and Redis**, or paste your own under **dekka.yaml** and choose **Plan blueprint**. Dekka shows everything it would create or change, and nothing exists until you deploy the plan from the same dialog.

```yaml title="dekka.yaml"
version: 1
name: Next.js with Postgres
variables:
  SENTRY_DSN: https://…
resources:
  - name: web
    kind: application
    spec:
      source: { repo_full_name: acme/storefront, branch: main }
      runtime: { port: 3000 }
    variables:
      NODE_ENV: production
      SENTRY_DSN: ${{shared.SENTRY_DSN}}
  - name: db
    kind: postgres
    spec: { version: "16", storage_mib: 100 }
connections:
  - { from: web, to: db }
```

Each resource's `spec` takes the same settings as the API, top-level `variables` become shared variables, and `connections` join a service to a database or bucket by name. Dekka reads a blueprint only when you paste it or send it to the API, never from the repository.

With the API, `POST /v1/blueprints/validate` checks a blueprint and lists every problem with its path, and `POST /v1/environments/{id}/blueprint/plan` compares it with the environment and returns the plan as a changeset, which you deploy with `POST /v1/changesets/{id}/deploy`. A plan only deletes what the blueprint leaves out when you send `"prune": true`, and a plan answers 409 `plan_stale` if the environment changed after it was made.
