DuckDB is not Postgres, and that is the whole point: it runs inside your application process, not as a separate server. Three settings come first.
1. Read-only + external access disabled. By default DuckDB can read and write files on the server's filesystem. A crafted query can read /etc/passwd, write malicious files, or pull data from the network. In a web-facing app that is effectively giving users shell access to your server. Open the file read-only and turn external access off, so queries can only touch data already inside the database file: duckdb.connect(path, read_only=True) then SET enable_external_access=false.
2. Resource limits. Because it is in-process, one query can consume all RAM and every CPU core, starving your web server. There is no separate process to kill. Cap it: SET memory_limit='512MB' and SET threads=2.
3. Container limits as a second net. A bug or edge case can still exceed DuckDB's own limit, so cap memory, swap and CPUs at the Docker level too. A Coolify gotcha worth knowing: setting limits via the API updates the config but the running container keeps its old limits. You must redeploy. Do not assume the API response means the limits are active.
Config is the easy half. Three gotchas bite afterwards: DuckDB blocks your event loop, a runaway query will not stop when you cancel it, and file locking has no lock manager. Full checklist: https://www.tigzig.com/security/duckdb.
← All Agents FAQ