DuckLess
Serverless DuckDB on GCP. Submit SQL or your own code; DuckLess runs it on a right-sized Compute Engine VM (Cloud Batch) in your project, reads and writes GCS through ADC (no HMAC keys), spills on local SSD, then tears the VM down. Nothing runs between jobs.
Status: early releases (v0.1.x). Changes are listed in the GitHub Releases;
spike/README.mdhas the measurements behind the design.
Quick start
uv tool install duckless # or: pip install duckless
duckless init --project my-project --region europe-west1
# prints the lines to put in .envrc (DUCKLESS_PROJECT, DUCKLESS_BUCKET, DUCKLESS_SA, DUCKLESS_IMAGE)
duckless preflight --machine n2-highmem-32 --spot
duckless run job.sql --machine n2-highmem-32 --spot
duckless exec --image <your-image> --machine n2-highmem-16 -- dbt build
duckless status <job-id>
duckless logs <job-id> --follow
duckless result <job-id>
duckless destroy --project my-project # removes what init created
init applies the Terraform module shipped with the CLI (duckless/terraform) through
Infrastructure Manager: no local Terraform, state kept in your project, re-run it to upgrade.
Teams managing infra as code can use the same module directly instead.
Writing jobs
- SQL (
.sql):${VAR}placeholders come from the job env (DUCKLESS_BUCKET,--env K=V). - Python (
.py):from duckless_runtime import connectgives a DuckDB connection with GCS auth, spill on local SSD, memory and threads sized to the VM. - Write to GCS in parallel:
COPY … TO 'gs://…' (FORMAT parquet, PER_THREAD_OUTPUT, FILE_SIZE_BYTES '256MB')is 7-8x faster than the single-writer default (~900 MB/s vs ~110 MB/s on 32 vCPU). - Vectorize Python logic: a row-wise Python UDF runs at ~8k rows/s on one thread; use an
Arrow UDF over numpy (
type="arrow") or SQL.
Layout
Hexagonal, kept light: a pure core, ports, adapters, and one wiring point.
| Path | What |
|---|---|
duckless/core/ |
Pure rules, no I/O: machine types and local SSD counts, job spec and planning, quotas, preflight |
duckless/ports.py |
What the service needs from outside: Executor, ArtifactStore, LogReader, QuotaReader (Protocols) |
duckless/service.py |
Operations shared by the CLI, the SDK and later the SaaS control plane: functions taking ports as arguments |
duckless/adapters/ |
GCP implementations: Cloud Batch, GCS, Cloud Logging, Compute quotas |
duckless/wiring.py |
Binds the service functions to the adapters (lazily) |
duckless/cli.py |
duckless command, a driving adapter |
runtime/ |
Runner image (duckless_runtime), published as ghcr.io/tosun-si/duckless-runner: DuckDB + gcs community extension, tuned for the VM |
duckless/terraform/ |
APIs, work bucket, least-privilege runner service account, Artifact Registry remote repository proxying the runner image |
spike/ |
The spike that validated the approach, kept as a record |
Dependency rule: core imports nothing else from DuckLess, service only core and ports,
and only wiring imports adapters.
Development
uv sync
uv run pytest
uv run ruff check . && uv run ruff format --check .
License: Apache-2.0
Metadata
Release files for duckless 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| duckless-0.1.1.tar.gz | 25.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| duckless-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.3 kB
Release files / duckless-0.1.1.tar.gz
| Download URL | duckless-0.1.1.tar.gz |
|---|---|
| Size | 25.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3f04c55c4c96eb68d041e0dc21b27303b144e4df6010a45274f172a2f9fa6bc4
|
|
BLAKE2b-256 checksum How to use checksums |
00bf7fcaaf37802dd1d85458e1ad6a68db5dee4dfde16764a91f782a27cd028d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / duckless-0.1.1-py3-none-any.whl
| Download URL | duckless-0.1.1-py3-none-any.whl |
|---|---|
| Size | 35.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bfdede98727f14df49a66110955f52a36e89e6b28871d254ccb9b8c2bac443eb
|
|
BLAKE2b-256 checksum How to use checksums |
ab69e9b4d0c076a349d8d410ae772fd971b7678fe678623d90bb1a10f06b27b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log