drift Docs
Start
What is Drift?
The tour, if you are new here.
Why Drift?
The case for a smaller cloud.
Getting started
Nothing to deployed, in one command.
Architecture
How a slice is put together.
What it costs
The free grant, five unit prices, two rules.
Build
Canvas
Static sites, same origin as your API.
Tools
Operate
Auth
Accounts, tokens and scopes.
Security
Boundaries, sandboxing and hardening.

Backbone data & state

The backbone section sets the data-layer limits and declares the resources to create: document collections, queues, secrets, and cache entries.

TypeDefaultMeaning
  • blob_max_size
    Type
    size
    Default
    platform default
    Meaning
    Maximum size of a single blob (file). A free safety quota, not a price driver.
  • blob_max_count
    Type
    integer
    Default
    platform default
    Meaning
    Maximum number of blobs the slice can store. A free safety quota, not a price driver.
  • queue_max_depth
    Type
    integer
    Default
    platform default
    Meaning
    Maximum messages in a single queue before producers are throttled.
  • secret_max_size
    Type
    size
    Default
    platform default
    Meaning
    Maximum size of a single secret value (e.g. 4KB).
  • locks
    Type
    integer
    Default
    platform default
    Meaning
    Maximum number of distributed locks held at once across the slice (the drift.Backbone.Lock primitive). Included and unpriced.
  • realtime_connections
    Type
    integer
    Default
    0 (off)
    Meaning
    Peak simultaneous live Realtime WebSocket connections across the slice, billed in blocks of 50. Omit or set 0 to disable Realtime.

There is no slice-wide storage limit. Storage is declared, priced, and enforced per item. Every nosql, sql, and blobs entry below carries its own mandatory size, which is both what you're billed for (summed across every item, charged per GiB) and the hard limit the platform enforces: a write past a given collection's, database's, or bucket's own size is rejected with 413, independent of every other item.

NoSQL collections

nosql is a list of maps, one per collection. size is required: it's both the billing driver and the enforced limit for that collection, so there's no default to silently fall back to. The long form also accepts a seed, a JSONL file (one JSON document per line) that the deploy upserts by each document's _id, and/or a ttl.

Driftfile
nosql:
    - name: submissions
      size: 200MB                              # empty collection
    - name: permit-types
      size: 20MB
      seed: ./backbone/permit-types.jsonl       # seeded from JSONL
    - name: sessions
      size: 20MB
      ttl: 30d                                  # reaped 30 days after last write
# permit-types.jsonl: one JSON document per line, each with an _id
{"_id": "residential-extension", "name": "Residential extension"}
{"_id": "new-build-residential", "name": "New-build residential"}

Seeding is idempotent (re-deploying re-upserts changed rows) and non-destructive (documents your app added at runtime are left alone, because their _ids aren't in the seed file). Every line must be valid JSON with a non-empty _id.

ttl (<int>s/m/h/d) deletes a document once its last write is older than the TTL. The clock resets on every update, so only genuinely stale, untouched documents are reaped. There's no undo: documents aren't soft-deleted or archived anywhere. Omit it and documents are kept forever. Applies per-collection, not per-document.

SQL databases

sql is a list of per-slice SQLite databases, addressed by name. Each entry materialises as one .db file and is reached from the SDK as drift.Backbone.SQL("name") for relational queries and transactions. size is required, on the same reasoning as nosql[].size: each database is billed and enforced on its own size, not against a shared slice-wide budget. The long form also accepts a schema and/or a seed.

Driftfile
sql:
    - name: app
      size:   100MB
      schema: ./backbone/app.sql        # idempotent DDL, runs on every deploy
      seed:   ./backbone/app-seed.sql   # runs only on the first deploy

schema is applied on every deploy, so keep it idempotent (CREATE TABLE IF NOT EXISTS …). seed runs only when the database has no user tables yet, which is the first deploy, so later deploys never re-run it, even if you change the file. To re-run a seed, start from an empty database again: drop it with drift backbone sql drop <name> and redeploy, and the deploy recreates the database and re-applies the schema and seed. A database name is 1–64 characters ([a-z0-9], then [a-z0-9_-], then [a-z0-9]) and becomes both the .db filename and the SDK lookup key.

TypeDefaultMeaning
  • name
    Type
    string
    Default
    required
    Meaning
    Database identifier and SDK lookup key, as in drift.Backbone.SQL("name").
  • size
    Type
    size (KB/MB/GB)
    Default
    required
    Meaning
    This database's own storage quota: the billing driver and the enforced limit. A write past it is rejected with 413.
  • schema
    Type
    path
    Default
    none
    Meaning
    SQL file of idempotent DDL, applied on every deploy.
  • seed
    Type
    path
    Default
    none
    Meaning
    SQL file run only on the first deploy (when the database has no user tables yet).

Read the Backbone SQL guide → for querying and transactions from your functions.

Blob buckets

blobs is a list of named buckets in the per-slice blob store, each with its own required size. Unlike nosql/sql, a bucket has no seed or schema. It exists purely to name a bucket and give it a quota before the first upload. Code doesn't reach a bucket through a handle the way SQL("name") does; drift.Backbone.Blob.Put/ .Get take one path-shaped name (e.g. "uploads/receipt-42.pdf"), where everything before the first / is the bucket, and a name with no / goes to the default bucket.

Driftfile
blobs:
    - name: uploads
      size: 500MB
TypeDefaultMeaning
  • name
    Type
    string
    Default
    required
    Meaning
    Bucket name: the prefix before the / in a blob's path-shaped name.
  • size
    Type
    size (KB/MB/GB)
    Default
    required
    Meaning
    This bucket's own storage quota: the billing driver and the enforced limit. A put past it is rejected with 413.

An undeclared bucket prefix (including default) is unquota'd, the same fallback as an undeclared nosql/sql name.

Queues

A list of names. Queues can't be seeded, because seeding messages on every deploy would re-fire work. There is no per-queue size: depth is bounded slice-wide by queue_max_depth.

Driftfile
queues:
    - validate                          # bare name
    - name: notify                    # long form: same thing, room to grow

The map form takes name and nothing else. It exists so per-queue options can arrive without breaking manifests; until they do, any other key inside it is rejected rather than ignored, so a typo fails the deploy instead of silently doing nothing.

Secrets

A map of KEY: value. A value of $NAME (unquoted) is a reference resolved when drift project deploy runs. The literal never touches the Driftfile or the wire, only the resolved string travels. Quote a value to force a literal that starts with $.

Driftfile
secrets:
    MUNICIPALITY_NAME: "Amsterdam"      # hardcoded literal
    RESEND_API_KEY:    $RESEND_API_KEY   # resolved at deploy time

A $NAME reference (and any ${VAR} placeholder elsewhere in the Driftfile) resolves through a variable origin hierarchy, highest precedence first:

  1. Hardcoded: a literal value written in the Driftfile. Absolute.
  2. Environment: a variable exported in your shell session.
  3. Override flags: --secret KEY=value (repeatable), and --env <name> (same as the positional environment; also sets ENV). An override yields to a variable the environment set; it beats the env files.
  4. .env.<env> file: when an environment is selected, the per-environment secrets file (e.g. .env.staging) next to the Driftfile. Out-ranks the base .env.
  5. .env file: the base KEY=value file next to the Driftfile, sourced automatically (lowest precedence; fills only what nothing above provided). Pass --no-env-file to skip the env files.

So an exported DB_PASSWORD beats --secret DB_PASSWORD=…, which beats a DB_PASSWORD line in .env.staging, which beats one in .env. A deploy prints what it loaded from which env file, and what it ignored because the environment supplied it, so the layering is never silent. Config dials that differ per environment belong in environments:; only secrets belong in .env.<env>.

Cache

A map from key to a value to pre-warm at deploy. The short form is a file path whose contents become the cached value. The long form takes an inline value (or a file) plus an optional ttl in seconds, after which the entry expires and a Cache.Get returns empty until your code re-populates it. Omit ttl (or set 0) for an entry that never expires.

Driftfile
cache:
    menu: ./backbone/menu.json          # short form: file contents become the value
    banner:                            # long form: inline value with a TTL
      value: "Closed for maintenance"
      ttl:   3600                       # seconds; 0 / omitted = never expires
    pricelist:                         # long form: file + TTL
      file: ./backbone/prices.json
      ttl:  86400

At runtime the cache is read/write from your functions, so these entries are just the initial warm set. Read the Backbone Cache guide →