Skip to main content

Derp

PyPI Python License Tests Docs

An async Python backend toolkit. One client, one config file.

ORM · Auth · Payments · Storage · KV · Queues · AI · CLI · Studio

Warning: Derp is in alpha. The API is unstable and may change without notice before 1.0.

Install

uv add derp-py

Requires Python 3.12+.

Quick Start

Define a table:

from derp.orm import Table, Field, Fn, UUID, Varchar, Integer, Boolean, TimestampTZ

class Product(Table, table="products"):
    id: UUID = Field(primary=True, default=Fn.gen_random_uuid())
    name: Varchar[255] = Field()
    price_cents: Integer = Field()
    is_active: Boolean = Field(default=True)
    created_at: TimestampTZ = Field(default=Fn.now())

Generate and apply a migration:

derp generate --name initial
derp migrate

Query data:

from derp import DerpClient, DerpConfig
from app.models import Product

config = DerpConfig.load("derp.toml")
derp = DerpClient(config)
await derp.connect()

# Select
products = await (
    derp.db.select(Product)
    .where(Product.is_active)
    .order_by(Product.created_at, asc=False)
    .limit(10)
    .execute()
)

# Insert
product = await (
    derp.db.insert(Product)
    .values(name="Headphones", price_cents=4999)
    .returning(Product)
    .execute()
)

# Update
await (
    derp.db.update(Product)
    .set(price_cents=3999)
    .where(Product.id == product.id)
    .execute()
)

Use with FastAPI

from contextlib import asynccontextmanager
from collections.abc import AsyncIterator
from fastapi import FastAPI, Request, Depends
from derp import DerpClient, DerpConfig

@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
    config = DerpConfig.load("derp.toml")
    derp = DerpClient(config)
    await derp.connect()
    app.state.derp = derp
    yield
    await derp.disconnect()

app = FastAPI(lifespan=lifespan)

def get_derp(request: Request) -> DerpClient:
    return request.app.state.derp

@app.get("/products")
async def list_products(derp: DerpClient = Depends(get_derp)):
    return await derp.db.select(Product).where(Product.is_active).execute()

Configuration

Everything lives in derp.toml. Only [database] is required — add modules as you need them:

[database]
db_url = "$DATABASE_URL"
schema_path = "app/models.py"

[auth.native]
enable_signup = true
[auth.native.jwt]
secret = "$JWT_SECRET"

[storage]
endpoint_url = "$S3_ENDPOINT"
public_urls = { assets = "https://assets.example.com" }
access_key_id = "$S3_KEY"
secret_access_key = "$S3_SECRET"

[kv.valkey]
addresses = [["localhost", 6379]]

[payments]
api_key = "$STRIPE_SECRET_KEY"

[queue.celery]
broker_url = "$CELERY_BROKER_URL"

[ai]
api_key = "$OPENAI_API_KEY"
# base_url = "https://api.openrouter.ai/v1"  # for other providers

Environment variables starting with $ are resolved at load time.

Modules

Auth

Email/password, magic links, Google/GitHub OAuth, JWTs, organizations. Native, Supabase, WorkOS, or Google Cloud Identity Platform (GCIP) backend — exactly one, selected by config.

user, tokens = await derp.auth.sign_up(email="alice@example.com", password="s3cure!")
session = await derp.auth.authenticate(request)  # from Bearer token
org = await derp.auth.create_org(name="Acme", slug="acme", creator_id=user.id)

Google Cloud Identity Platform (GCIP) is a hosted IdP backend (a peer of Supabase/WorkOS). It verifies Google-issued RS256 ID tokens locally, runs user-facing flows through the API-key Identity Toolkit endpoints, and user administration through a service-account-signed token. GCIP sends its own magic-link and password-reset emails, so — unlike the native backend — it does not require an [email] block. It has no organization concept, so the org methods raise NotImplementedError.

[auth.gcip]
project_id = "$GCIP_PROJECT_ID"
api_key = "$GCIP_API_KEY"                       # GCIP Web API key
service_account_json = "$GCIP_SERVICE_ACCOUNT_JSON"  # full SA key JSON
# redirect_uri = "https://yourapp.com/callback"

Payments (Stripe)

customer = await derp.payments.create_customer(email="buyer@example.com")
session = await derp.payments.create_checkout_session(
    mode="payment",
    line_items=[{"price_id": "price_xxx", "quantity": 1}],
    success_url="https://example.com/success",
    cancel_url="https://example.com/cancel",
)
event = await derp.payments.verify_webhook_event(payload=body, signature=sig)

Storage (S3)

await derp.storage.upload_file(bucket="assets", key="avatar.jpg", data=img, content_type="image/jpeg")
data = await derp.storage.fetch_file(bucket="assets", key="avatar.jpg")

# Signed URLs for direct client access
url = await derp.storage.signed_download_url(bucket="assets", key="avatar.jpg")
url = await derp.storage.signed_upload_url(bucket="assets", key="uploads/new.jpg", content_type="image/jpeg")

# Batch delete and server-side copy
await derp.storage.delete_files(bucket="assets", keys=["tmp/a.txt", "tmp/b.txt"])
await derp.storage.copy_file(src_bucket="uploads", src_key="tmp.jpg", dst_bucket="assets", dst_key="final.jpg")

KV (Valkey)

await derp.kv.set(b"user:123", b'{"name":"Alice"}', ttl=3600)
data = await derp.kv.get(b"user:123")

# Idempotent endpoints
body, status, is_replay = await derp.kv.idempotent_execute(
    key=idem_key, compute=lambda: create_order(data), status_code=201,
)

# Webhook dedup
if await derp.kv.already_processed(event_id=event["id"]):
    return {"status": "duplicate"}

# Rate limiting
result = await derp.kv.rate_limit(f"api:{user.id}", limit=100, window=3600)
if not result.allowed:
    raise HTTPException(429, headers={"Retry-After": str(result.retry_after)})

AI (OpenAI / Fal / Modal)

# Chat
response = await derp.ai.chat(model="gpt-4o-mini", messages=[{"role": "user", "content": "Hello"}])
print(response.content)

# Streaming with Vercel AI SDK format
async for chunk in derp.ai.stream_chat(model="gpt-4o-mini", messages=messages):
    for event in chunk.vercel_ai_json(message_id="msg-1"):
        yield event.dump()  # "data: {...}\n\n"

# Image generation via fal (submit + poll + get in one call)
result = await derp.ai.fal_call("fal-ai/flux", inputs={"prompt": "a cat"})

Queue (Celery / Vercel)

task_id = await derp.queue.enqueue("send_email", payload={"user_id": str(user.id)})
status = await derp.queue.get_status(task_id)

Schedules in config:

[[queue.schedules]]
name = "cleanup"
task = "cleanup_sessions"
cron = "0 */6 * * *"

CLI

derp init          Create derp.toml
derp generate      Generate migration from schema diff
derp migrate       Apply pending migrations
derp push          Push schema directly (dev only)
derp pull          Introspect database into snapshot
derp status        Show migration status
derp check         Verify schema matches snapshot (CI)
derp drop          Remove migration files
derp studio        Launch database browser UI
derp version       Show version

Documentation

Full docs at derp.readthedocs.io.

Development

uv sync
uv run pytest
uv run ruff check src/
uv run ruff format src/

License

MIT

Metadata

Release files for derp-py 0.2.15

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for derp-py 0.2.15
File Size Uploaded Provenance Actions
derp_py-0.2.15.tar.gz 255.6 kB With provenance Details for derp_py-0.2.15.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for derp-py 0.2.15
File Interpreter ABI Platform Actions
derp_py-0.2.15-py3-none-any.whl Python 3 none any Details for derp_py-0.2.15-py3-none-any.whl

Total release size: 575.7 kB

Release files / derp_py-0.2.15.tar.gz

Download URL derp_py-0.2.15.tar.gz
Size 255.6 kB
Tags Source
SHA-256 checksum
How to use checksums
75f475fd63498a2a35954854a37d68b5fbd3c259bd72b18268380dcf7c337e5e
BLAKE2b-256 checksum
How to use checksums
cf223cd1b6e33fad7cbd9c4faa845f49516e50ab07d2fbabaf6178d4765a3444
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jul 12, 2026.

Transparency log

Release files / derp_py-0.2.15-py3-none-any.whl

Download URL derp_py-0.2.15-py3-none-any.whl
Size 320.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6a7167855d85936fa2bf5dac24e5ceb8f0bf8c7f53b70bc41d8412d3a403585e
BLAKE2b-256 checksum
How to use checksums
b907e9704c7b5d8a38e5729a719f387a50bf50609944e19be410719063ef095a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jul 12, 2026.

Transparency log

Security for derp-py 0.2.15

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for derp_py-0.2.15.tar.gz

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 Jul 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page