drift Docs
Start
What is Drift?
The tour, if you are new here.
Use cases
Whether Drift does your thing.
Getting started
Nothing to deployed, in one command.
Architecture
How a slice is put together.
What it costs
The free grant, four unit prices, two rules.
Build
Canvas
Static sites, same origin as your API.
Tools
Operate
Auth
Route gates, API keys and your account.
Security
Boundaries, sandboxing and hardening.
Troubleshooting
Error codes
What went wrong, and what to do about it.
Legal
Acceptable use
What a slice may not be used for.
Data processing
The DPA, and every sub-processor.

Backbone

Backbone is your slice's encrypted data layer. Your functions reach it through the SDK with a single call: no connection strings, no ORM, no migrations. Queues and SQL databases spring into existence the first time you use them. NoSQL collections and blob buckets are part of the slice's shape instead, so they have to exist before you can write to them; a write naming one the slice does not have is refused rather than creating it. Seed and inspect any of them from the CLI.

The primitives

Each primitive has a drift backbone <name> command group of its own, and the whole surface is in the CLI reference. Inspect your slice's data and usage any time with drift backbone status.

Calling Backbone from a function

Each SDK spells the namespace the way its language does. The same insert, six ways:

Language Call
Godrift.Backbone.NoSQL.Collection("users").Insert(doc)
Pythondrift.backbone.nosql.collection("users").insert(doc)
Nodeawait drift.backbone.nosql.collection("users").insert(doc)
RubyDrift::Backbone::Nosql.collection("users").insert(doc)
PHP\Drift\Backbone\Nosql::collection("users")->insert($doc)
Rustdrift_sdk::backbone::nosql::collection("users").insert(json)

Every Node Backbone call returns a promise, so await it. The examples on each primitive's page are Go; the table above translates them.

Limits you cannot declare

The quotas you buy in the slice's shape (collection and bucket sizes, queue depth, realtime connections) run inside a set of fixed caps built into the slice. These are the same on every tier and there is no key for them.

Primitive Fixed cap
Cache1 MiB per value · 10,000 entries · 64 MiB of total value bytes
NoSQLlist returns 100 by default, 1,000 maximum
SQL64 KiB per statement · a transaction idle for 30 s is rolled back
Realtime512 KiB per message · 128 connections per channel · 2,048 channels per slice
Queue triggerspolled every 500 ms · 3 attempts, then <queue>-dlq

Names are validated on the way in, and the charset differs by what the name becomes:

Name Charset
Collection, queue, bucket, NoSQL _keyFirst character alphanumeric, then alphanumerics . _ -, up to 255 bytes.
Blob keyThe same plus /, up to 513 bytes, no ...
Indexed field nameFirst character alphanumeric or _, then alphanumerics . _ -, up to 255 bytes, no ...
Indexed value (NoSQL _id included)Up to 255 bytes. No charset restriction: an email address, an ISO timestamp, a path all index and filter normally.
Realtime channelAlphanumerics and : . _ ~ -, up to 256 bytes.
LockAny non-empty string.

Status codes

The primitives share one status contract, so a code tells you what went wrong without reading the message. The SDKs carry it into the error they return; the CLI prints it.

Code Meaning
200Done. A read carries the value; queue push carries the message id.
204Nothing to return: an empty queue on pop or peek, a successful NoSQL delete, a successful SQL commit or rollback.
400Bad request: malformed JSON, a missing parameter, a name outside its charset, an unindexable filter, an unknown transaction token, or an error from SQLite.
401The route is internal. A function reaching for a secret it did not declare, or calling Secret.Set, lands here.
404No such key, blob, queue or lock.
409The lock is held by someone else, or the write collides with a collection's unique constraint.
413Too big: a collection or bucket at the size you gave it, or a SQL statement over the fixed 64 KiB cap.
429Over a platform cap: cache full, queue at its depth limit, concurrent-lock cap, or too many SQL databases.
503The slice is at its realtime connection cap, or draining.

Backbone under drift atomic run

Local dev has no slice behind it. Every SDK answers Backbone calls from an in-memory store inside your own process, which behaves differently from a deployed slice in ways worth knowing before you trust a green local run:

Local Deployed
State lives in the process and is lost on exit. Nothing is encrypted.Encrypted at rest with the slice's own key, and durable.
Insert returns a key.Insert returns an empty string.
No quotas, no TTL expiry, none of the caps above.All of them enforced.
Secrets are read from the environment; the CLI loads .env from your source directory.Declared secrets arrive as DRIFT_SECRET_<NAME> (every language), and in req.secrets everywhere but Go.
SQL has no local implementation.SQLite per database, encrypted at rest.
Blobs live in a per-SDK scratch map, and Go's Blob.Put stores nothing at all.Stores the bytes, encrypted.
No realtime hub: Publish and Presence report 0.Fans out to live subscribers.

Anything that depends on those differences needs a deployed slice to test against.

What a snapshot captures

drift slice snapshot create archives secrets, NoSQL collections, blobs, queues and SQL databases. Cache and locks are not in the archive, because both hold data that is recomputable or short-lived by design, so restoring a snapshot gives you a cold cache and no held locks.

Blobs are captured from the same top-level bucket listing the CLI uses, so a key containing a slash is absent from the archive as well as from blob list.