Skip to main content

fakesnow

Intro​

Depot Local can serve a Snowflake location from fakesnow — a local Snowflake emulator built on DuckDB and SQLGlot — instead of a Snowflake account. Depot Local starts the container, creates the databases, and writes the connection details the connector reads, so a suite that exercises the Snowflake path needs no account, no private key, no AWS profile and no depot.properties of your own.

The location itself is an ordinary SNOWFLAKE location. Nothing about your schema, your environment or your requests changes — only where the connection points. A package that already has Depot Local Snowflake tests needs one config field and one line at the location.

info

This is the Depot Local flavour. For a Depot Test suite — DepotTest.in(namespace)… with setContent and check steps — use the FAKESNOW location type instead, where the Depot Test backend owns the container. The two are separate surfaces; this page is only about DepotLocal.

The caution on the Snowflake page still applies: a Depot Local Snowflake test is slower than the equivalent Depot Test transaction test, so reach for it when a transaction test cannot express what you need — queries, the lambda or GQL API, the gateway interface.

Example​

Add fakesnow to the config, and every Snowflake location in the run points at the container:

const depot = new DepotLocal({
depot: {},
// dynamodb is required for snowflake tests
dynamodb: {},
fakesnow: {} // starts the fakesnow container and points Snowflake locations at it
});

beforeAll(async () => {
await depot.start();
});

afterAll(async () => {
await depot.stop();
});

Build the environment with a fakesnow-served location:

const namespace = Schemas.fromYamlFiles("test/schema/pet.yml");
const environment = new EnvironmentBuilder(namespace)
.location(LocationBuilder.fakesnowDb())
.build();

const api = depot.deploy(environment).api(0);

const create = await api.create({
schema: "pet.Pet",
data: {name: "Bandit", age: 3}
});

LocationBuilder.fakesnowDb() names the intent, so a test says what it runs against; it returns the same SNOWFLAKE location snowflakeDb() does. Use LocationBuilder.fakesnow(id) when you need to choose the location id yourself.

deploy() only registers the environment — the connector deploys the schema on the first request, so the DDL runs against fakesnow when your first api call arrives, not at deploy().

For a working example, see packages/depot-local/test/fakesnow.test.ts.

What Depot Local does for you​

Worth knowing, because each of these is a thing you would otherwise have to do by hand:

  • Starts the container on the run's Docker network. The connector reaches it by network alias rather than localhost — the two are in different containers — while your test process reaches it on a host port Docker assigns, so concurrent runs do not collide.
  • Creates the databases. Snowflake refuses USE DATABASE for a database that does not exist and so does fakesnow; on a real account someone created it once, by hand. Depot Local creates DEPOT_TEST before the connector starts.
  • Writes the depot.properties the connector reads, into the directory it mounts at /env: sql.endpointOverride plus fakesnow's fixed credentials. The connector then stamps those onto every Snowflake executor in the environment. Your own depot.properties, if you have one, is not involved and not read.

The credentials are fixed and carry no secret: account fakesnow, user fake, password snow, database DEPOT_TEST, warehouse DEPOT_TEST_WH. Password auth, so no key pair anywhere.

caution

fakesnow and a real Snowflake are mutually exclusive for a run. Depot stamps one set of Snowflake credentials over every Snowflake executor in the environment, so an environment cannot have one location on fakesnow and another on an account.

What works, and what does not​

It is the same emulator the FAKESNOW location type uses, so the parity boundaries are the same ones that page lists — no S3 behind a stage (so no export), no stored procedures, and Snowflake's proprietary HASH values differ, since fakesnow computes DuckDB's hash. A test that asserts a recorded Snowflake hash belongs on a real account.

One Depot check does not run: Depot normally compares each view's stored DDL against the text it submitted, and only Snowflake echoes that text verbatim. Pointing at any endpoint override skips that comparison. Data checks are unaffected.

Options​

VariableEffect
DEPOT_FAKESNOW_IMAGERun a fakesnow image of your own instead of the pinned one, e.g. fakesnow:local. The same variable the Java side reads, deliberately.
DEPOT_FAKESNOW_MEMORYThe container's memory limit, such as 2g or 1536m: whole bytes, or a whole number with k, m or g (binary). Unset, no limit. The same variable the Java side reads.
DEPOT_FAKESNOW_DEBUGPassed to the container as FAKESNOW_DEBUG for fakesnow's own SQL tracing: snowflake to see each statement as Depot sent it, anything else to see the DuckDB SQL it was translated into.
DEPOT_LOCAL_VERSIONOverrides the connector image version. See the troubleshooting note below.

With a memory limit, DuckDB gets about 70% of it and spills to disk past that. A container that needs more than its limit is killed, and the tests then fail on a lost connection rather than an out-of-memory error, so raise the limit if that happens. The limit applies to a container the run starts: one reused through DEPOT_LOCAL_KEEP_ALIVE keeps the limit it started with. The Java side picks a budget of its own when the variable is unset.

fakesnow: { showLogs: true } brings the container's output into your test log. port, strictHostPort and containerPort behave as they do for the other services, though there is rarely a reason to pin the port — nothing outside the run connects to it.

Troubleshooting​

No credentials defined for dataset … default executor depot-local-snowflake-executor

The connector image is older than the fakesnow support: sql.endpointOverride means nothing to it, so it discards the credentials Depot Local wrote and the executor reaches the request with none.

The image version comes from @stage-tech/depot-config's platformVersion — but from the copy in your workspace's node_modules, which a yarn install can leave older than packages/depot-config. Nothing keeps the two in step, so a run can silently use an image from weeks before the pin. Check which one you have, and until it is refreshed, override it:

DEPOT_LOCAL_VERSION=<the version packages/depot-config pins> yarn vitest run test/fakesnow.test.ts

Suspect this before suspecting the wiring — the symptom appears several layers from the cause, and the wiring is pinned by tests on the platform side (FakesnowCredentialsTest).

A create returns 409 for a row that is not there

A write reports its row count through the JDBC driver, and Depot reads anything but 1 as "this object already exists". Fixed in the fakesnow image; if it reappears, you are on an older image than the pinned one — check DEPOT_FAKESNOW_IMAGE.

Catalog Error: … does not exist for a database other than DEPOT_TEST

Depot Local creates DEPOT_TEST only. A schema that names a different database needs it created first — fakesnow, like Snowflake, will not conjure one.