Integrations
A project manager can connect a data source once for one project. A super admin can connect a data source for the whole organization. Supported sources include the common SQL databases and warehouses (PostgreSQL, MySQL, SQL Server, MongoDB, ClickHouse, Snowflake, BigQuery, Redshift, MotherDuck), query engines (Trino, Spark Connect, Databricks SQL, Athena), PyIceberg catalogs, object storage (S3, GCS, Azure Blob), remote DuckDB databases and DuckLake catalogs, ML platforms (Weights & Biases, Hugging Face), and environment variables.
Each new, non-ephemeral session receives the applicable connection configuration as environment variables and files. Notebook code never accesses the hub API or storage. The hub injects configuration, not Python libraries. Each kind lists the required packages below. Add those packages to the notebook dependencies.
Integrations are enabled by default. Set MARIMOHUB_INTEGRATIONS=off to make the routes return 404 and prevent integration configuration from being injected into sessions. Older releases also accepted true and none. Before upgrading, replace those aliases with on and off; this release no longer accepts them.
Integration configuration is versioned. Each save creates an immutable revision. Each session records the revisions that it uses.
Browse data
MARIMOHUB_DATA_BROWSER=metadata is the default: the Data page and browse API are enabled for metadata. Set it to full to also enable row previews, object previews, and object downloads, or to off to disable browsing. Browsing requires integrations and an integration probe that is not off. The default yields silently when integrations or the probe are off; an explicit metadata or full setting fails at startup instead.
Editors and higher roles can use the Data page at /projects/{pid}/data. They do not need a notebook session. The URL stores the selected integration, surface, item, and search scope. A shared link restores the same view.
For catalog integrations, the Data page lists namespaces, tables, and schemas. The schema view shows columns, partition fields, and available snapshot statistics. S3 and GCS use buckets, prefixes, and objects. Azure Blob uses containers, prefixes, and blobs.
Each detail view provides notebook code for the selected table or object. Open in notebook creates and opens a notebook with this code. Before you run the notebook, add the packages listed for that integration kind.
Browsing is read-only. Iceberg REST and ClickHouse use HTTP GET requests. Trino submits hub-generated SHOW, DESCRIBE, and bounded SELECT statements. All requests use the egress policy from MARIMOHUB_INTEGRATIONS_PROBE.
Catalog browsing
The hub supports Iceberg REST Catalog, Trino, and ClickHouse. Trino uses the catalog → schema → table hierarchy. ClickHouse uses database → table.
The hub cannot browse an Iceberg REST integration that uses:
- SigV4, Google, or Entra authentication
- a custom CA or client certificate
These configurations continue to work in notebook sandboxes.
Trino browsing supports no authentication, Basic authentication, and JWT with system TLS. OAuth2, client certificates, Kerberos, GSSAPI, and custom TLS are sandbox-only. ClickHouse requires certificate verification when using HTTPS. Password authentication also requires HTTPS.
The GET …/integrations/{iid}/browse route reports the capabilities of one integration and explains why a capability is unavailable.
Object-store browsing
S3, GCS, and Azure Blob browsing supports these read-only operations:
- Navigate configured or accessible roots and prefixes.
- Search a bounded number of object names.
- Read metadata, tags, and version history.
- Load explicit previews and notebook snippets.
- Stream downloads through the hub.
The browser cannot upload, delete, restore, rename, or edit upstream objects or metadata.
The API retains bucket, key, and version_id as provider-neutral compatibility fields. The UI calls Azure roots containers. Copied and detail URIs use s3://, gs://, and az:// respectively.
When an S3 integration sets bucket, the browser exposes only that bucket and does not call ListBuckets. This is a user-interface scope, not an IAM restriction: notebook code still has every permission granted to the integration credentials. Without bucket, the browser calls ListBuckets and shows the accessible result.
Metadata mode prevents the hub from returning object bodies. Full mode permits explicit previews and downloads. S3 authorizes HeadObject with the same read actions as content. Thus, IAM cannot grant separate metadata-only HEAD access. Grant only the actions required by the selected features:
s3:ListAllMyBucketswhen the integration has no configured bucket.s3:ListBucketfor prefixes and bounded key-name search.s3:GetObjectfor current-object metadata, previews, and downloads.s3:GetObjectVersionfor selected-version metadata, previews, and downloads.s3:ListBucketVersionsfor version history.s3:GetObjectTaggingto show tags. A denied tag request does not hide other metadata.
Substring search is a bounded recursive S3 listing, not a persistent index or content search. The Data page reports how many keys were scanned and whether more keys may exist. Continue the search to scan the next bounded segment. Prefix navigation uses S3's native Prefix operation and is less expensive.
Selecting an object performs metadata reads only. Content is fetched after Load preview or Download. CSV, TSV, JSON, JSON Lines, Parquet, UTF-8 text/code/Markdown/logs, and magic-byte- validated PNG, JPEG, GIF, and WebP files can be previewed within configured byte, row, column, request, result, and deadline limits. HTML, SVG, PDF, archives, executables, unknown binary files, and oversized images are never rendered inline. Truncated previews say so.
Downloads remain behind hub authorization and stream through the server. They support one HTTP byte range and preserve ETag or version preconditions. They also use safe attachment filenames and propagate client cancellation upstream. The hub does not return provider credentials or presigned URLs.
The raw content endpoint is GET /api/v1/projects/{pid}/integrations/{iid}/browse/objects/content. It requires bucket and key; version_id, etag, and inline=true are optional. Editors and higher roles can send one Range: bytes=… header and receive 200 or 206. Pre-stream failures use the standard JSON error envelope, including 403, 404, 412, 416, 429, and 503 responses.
Static integration credentials are used only for that integration. S3 ambient-auth integrations use short-lived project WIF credentials when the project enables a compatible target. The WIF storage endpoint and integration endpoint must be the same canonical origin. Otherwise, ambient object browsing for S3 remains unavailable unless the operator explicitly sets MARIMOHUB_OBJECT_BROWSER_ALLOW_SERVER_AMBIENT_CREDENTIALS=true. That setting grants project editors access through the control-plane AWS identity. Enable it only when that access is intentional.
GCS service-account integrations use storage.buckets.list for discovery. They use storage.objects.list for navigation and versions. They use storage.objects.get for metadata and content. Ambient GCS uses ADC only when the server-ambient option is enabled. Bucket discovery requires a project ID from the integration, service-account key, ADC environment, or metadata service. GCS generations map to version_id. Version history uses the native versions=true listing and has no delete-marker records.
Azure supports account keys, SAS tokens, connection strings, service principals, and DefaultAzureCredential. Grant container listing only when discovery is needed, blob listing for navigation and versions, and blob read/tag permissions for metadata and content. Azure blob version IDs map to version_id; accounts without Blob Versions return an empty terminal history while current blobs remain browsable. Soft-deleted blobs are not labeled as S3 delete markers.
Server-ambient browsing gives project editors the hub control-plane identity for each ambient provider. GCS accepts standard ADC service-account, authorized-user, external-account, and metadata credentials. GCS external accounts and Azure Entra tokens can expose every object that these identities can read. Keep this option off unless that access is intentional. Provider data traffic uses the guarded resolver. Provider SDKs manage ambient authentication. Azure Entra traffic is limited to fixed authority hosts. All browser operations are read-only.
Custom endpoints use the configured guarded/private integration egress policy. guarded rejects private, loopback, link-local, metadata, and other reserved targets. Use private only when an on-premises S3-compatible endpoint must be reachable. Every final SDK hostname, including generated virtual-host names and retries, is resolved, checked, and pinned before transport.
Successful object previews and opened downloads create integration.object.preview and integration.object.download audit events. Routine listing, search, and metadata navigation do not. Object content, credentials, signed headers, and provider error text are not stored in browse caches or audit events.
S3-compatible implementations can omit bucket discovery, tags, checksums, or versioning. If ListBuckets is unavailable, configure a bucket. The Data page shows optional features that the target or credentials do not support. For a private endpoint timeout, make sure that the probe is set to private. Then make sure that server DNS and TLS trust are correct. See the object-browser limits in Configuration.
Row previews
The Preview tab does not load data automatically. Select Load preview to request rows. The response is not cached, and a successful request creates an audit event.
Trino and ClickHouse run bounded preview queries through their HTTP APIs. Other browsable integrations emit a runtime-specific preview program. The preview service prefers DuckDB-Wasm SQL when the runtime supports every required feature, then falls back to a new sandbox running a fixed Python program.
The DuckDB executor is enabled by default in full data-browser mode.
The Node server uses a worker thread. Blocking inline execution is unavailable because a query cannot be preempted at its deadline. Each query runs in a read-only transaction after the runtime sets its memory limit and locks configuration. The unbrokered runtime disables external access and rejects remote Node file callbacks.
The brokered runtime supports explicit S3 storage. It requires all these values:
- no authentication, bearer-token authentication, or OAuth2 client credentials
- no access delegation
- explicit S3 storage with an origin-only endpoint, using path-style or virtual-hosted addressing
- static S3 credentials or anonymous access
- one or more guarded S3 read locations
- system TLS and default runtime options
Switch Storage from the default catalog scheme to s3 before you configure the brokered profile. The storage.broker_read_locations field only appears on that s3 branch; set it to the bucket prefixes that DuckDB can read. Set Access delegation to none. The worker receives no real catalog or S3 credentials. The parent broker authorizes each request, injects credentials, checks DNS results, and pins the target socket. Authenticated catalog, OAuth2, and S3 endpoints require HTTPS by default. Enable allow_insecure_transport only for local development.
Upgrade note: Stored authenticated HTTP S3 configurations keep their current behavior. The schema migration enables
allow_insecure_transportfor those configurations. New configurations must enable this option explicitly.
For OAuth2, the parent owns the client secret and refreshes the access token. The token endpoint uses the configured integration egress policy. Access tokens stay in one broker session. The worker receives only the dummy token from the generated ATTACH statement.
The broker also supports S3 credentials from a trusted Iceberg REST catalog. Configure this path as follows:
storage:
scheme: catalog
vended_s3:
endpoint: https://s3.us-east-1.amazonaws.com
region: us-east-1
force_virtual_addressing: true
allowed_locations:
- bucket: warehouse
prefix: production/
access_delegation: vended_credentialsEach allowed location is a maximum bound. The catalog cannot grant a sibling prefix, bucket, or endpoint. An empty prefix grants its complete bucket.
The catalog must use HTTPS. The storage endpoint must be an HTTPS origin. The broker supports path-style and virtual-hosted S3 requests.
The broker reads prefixes from LoadTable and table-credentials responses. It installs each route before DuckDB reads an object. The parent does not store the credential values.
Only SigV4 authorization, date, payload-hash, and session-token headers enter dynamic storage routes. These headers cannot enter catalog routes or unmatched storage routes.
GCS, Azure storage, remote signing, server-side scan responses, and worker-selected endpoints are not supported. These configurations use the Python executor.
Bounded vended routes are available when guarded DuckDB HTTP is enabled. R2 Data Catalog routes use a bound from the catalog URI instead of configured allowed_locations.
Other Iceberg configurations continue to use the sandbox executor.
Sandbox previews require MARIMOHUB_DATA_PREVIEW_IMAGE. The image must contain Python, PyIceberg, and PyArrow. The compute backend must support per-sandbox OCI image overrides. The local, e2b, none, and noop backends do not support them.
At startup, the hub verifies each configured executor before advertising it. Each preview receives the selected integration configuration and applicable WIF credentials. Concurrency limits and deadlines bound resource use. The hub destroys the sandbox after the request, including after a failure.
Run SQL
The POST …/integrations/{iid}/browse/query operation is always present in the API contract. It returns 404 unless integrations are enabled and full data browsing is selected:
MARIMOHUB_DATA_BROWSER=fullOAuth2 Iceberg catalogs and S3 object queries are enabled with full data browsing. To take a capability away from one integration, disable that integration.
Only project managers and administrators can run SQL. Each request receives a fresh DuckDB-Wasm worker, runs one statement in a read-only transaction, and is hard-terminated at its deadline. Direct remote callbacks, automatic extension installation, automatic extension loading, and configuration changes are disabled. Brokered Iceberg and S3 plans can load only pinned local extensions and approved URLs. Row, response-byte, concurrency, per-user, memory, and time limits apply. Successful queries create an audit event that records sizes and row counts, never SQL text.
Remote DuckDB database files
The duckdb_http integration attaches one database file as a read-only DuckDB catalog for Run SQL. It does not expose schema browsing or inject configuration into notebook sessions. Enable full data browsing to use Run SQL:
MARIMOHUB_DATA_BROWSER=fullConfigure an exact object URL:
url: https://data.example.com/snapshots/2026-08-27/analytics.duckdb
auth:
method: bearer_token
token: secretThe URL must use HTTPS. It cannot contain embedded credentials, query parameters, a fragment, encoded path separators or dot segments, or a trailing slash. Its normalized path must end in .duckdb unless the advanced suffix override is enabled. Authentication can be none, bearer_token, or basic. Bearer tokens and Basic passwords stay in the parent process. The DuckDB worker cannot read them.
The broker authorizes only the normalized URL, not its origin, parent path, or sibling files. GET and HEAD are the only methods. Redirects are rejected because the target would be outside the exact object capability. The server must support single byte ranges, return valid Content-Range values for 206 responses, and return one strong ETag on every successful response. Weak or missing ETags, multipart ranges, inconsistent lengths, changed ETags, and 412 Precondition Failed responses stop the query. After the first response, the broker sends If-Match on every later request.
One query can make at most 512 remote requests, with 4 in flight, and receive at most 64 MiB in total. One response is limited to 16 MiB. A server that ignores a GET range is accepted only when the complete object is at most 1 MiB. The database does not need to fit in memory, but a query that reads more than the cumulative budget fails. Keep remote databases at or below 1 GiB and test representative scans against the 64 MiB read budget.
Publish new snapshots at new versioned paths and retain old snapshots while queries can still be running. Replacing bytes at the same URL is safe between queries, but replacement during a query fails the ETag precondition. A static Nginx location can preserve old files and provide ranges and strong ETags:
location /snapshots/ {
alias /srv/duckdb-snapshots/;
etag on;
max_ranges 1;
add_header Cache-Control "public, max-age=31536000, immutable";
}Write each snapshot to a new directory before publishing its URL. Do not overwrite or delete a snapshot until the longest possible Run SQL request has ended.
duckdb_http · database · config schema v1
Remote DuckDB Database configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | Exact HTTPS URL of one immutable DuckDB database file | |
auth.method | none, bearer_token, basic | Yes | ||
allow_non_duckdb_suffix | boolean | false | Allow a URL path that does not end in .duckdb |
auth.method: bearer_token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
auth.method: basic
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.username | string | Yes | ||
auth.password 🔒 | string | Yes |
DuckLake
The ducklake integration reads one DuckDB metadata catalog and its S3 data files. The integration is available only for Run SQL. It does not add files or variables to notebook sessions. It has no Test connection action. Run a query to verify access.
The pinned DuckDB 1.4.3 extension supports DuckLake specification version 0.3. It does not support automatic migration. Create the metadata catalog with DuckDB 1.4.3.
Configure an immutable metadata URL and explicit S3 bounds:
metadata:
type: duckdb
url: https://data.example.com/catalog/releases/42.ducklake
auth:
method: bearer_token
token: secret
storage:
scheme: s3
endpoint: https://s3.us-east-1.amazonaws.com
region: us-east-1
force_virtual_addressing: true
credentials:
method: static
access_key_id: secret
secret_access_key: secret
broker_read_locations:
- bucket: warehouse
prefix: ducklake/data/
snapshot:
version: 42The metadata URL uses the same exact-object policy as duckdb_http. The server must return single byte ranges and one strong ETag. The broker rejects redirects, changed objects, and sibling paths.
The S3 endpoint must be an HTTPS origin. Each read location grants one bucket prefix. The broker rejects requests outside these locations, even if the metadata catalog contains another path.
The worker receives dummy S3 credentials. The parent broker adds the real S3 signature to approved requests. Metadata authorization cannot enter an S3 request. S3 authorization cannot enter a metadata request.
DuckLake attaches the catalog with READ_ONLY and CREATE_IF_NOT_EXISTS false. The integration does not set DATA_PATH or OVERRIDE_DATA_PATH. The extension reads the data path from the metadata catalog.
Set snapshot.version or snapshot.timestamp to read a historical snapshot. Do not set both fields. Omit both fields to read the latest snapshot.
SQLite metadata and standalone SQLite files are not supported. The pinned SQLite extension cannot open a DuckDB-Wasm buffer registration. This restriction prevents host-path access and accidental database creation.
ducklake · database · config schema v1
DuckLake configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
metadata.type | duckdb | Yes | Metadata catalog format. Only DuckDB catalog files are supported. | |
metadata.url | string | Yes | Exact HTTPS URL of one immutable DuckLake metadata file | |
metadata.auth.method | none, bearer_token, basic | Yes | How the hub authenticates to the metadata URL. Never forwarded to S3 requests. | |
metadata.allow_non_database_suffix | boolean | false | Accept a metadata URL that does not end in .ducklake or .duckdb. | |
storage.scheme | s3 | Yes | Data-file storage scheme. Only S3-compatible storage is supported. | |
storage.endpoint | string | Yes | Origin-only HTTPS S3 endpoint, e.g. https://s3.us-east-1.amazonaws.com. | |
storage.region | string | Yes | AWS region used to sign S3 requests, e.g. us-east-1. | |
storage.force_virtual_addressing | boolean | true | Address buckets as {bucket}.{endpoint} (virtual-hosted style) instead of {endpoint}/{bucket} (path style). | |
storage.credentials.method | static | Yes | Credential source. Only static keys are supported. | |
storage.credentials.access_key_id 🔒 | string | Yes | AWS access key ID. Held by the hub broker; never sent to the notebook worker. | |
storage.credentials.secret_access_key 🔒 | string | Yes | AWS secret access key. Held by the hub broker; never sent to the notebook worker. | |
storage.credentials.session_token 🔒 | string | AWS session token for temporary credentials. | ||
storage.broker_read_locations | object[] | Yes | Bucket prefixes the broker may read data files from. Requests outside these locations are rejected. | |
storage.broker_read_locations[].bucket | string | Yes | ||
storage.broker_read_locations[].prefix | string | Yes | ||
snapshot.version | integer | Read this DuckLake snapshot version instead of the latest snapshot. | ||
snapshot.timestamp | string | Read the snapshot current at this RFC 3339 timestamp instead of the latest. |
metadata.auth.method: bearer_token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
metadata.auth.token 🔒 | string | Yes |
metadata.auth.method: basic
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
metadata.auth.username | string | Yes | ||
metadata.auth.password 🔒 | string | Yes |
DuckDB remote-read errors
Remote-read errors include a stable code and a safe explanation. They do not include credentials, object paths, endpoint URLs, or OAuth2 response bodies. This table lists every code returned to Run SQL callers.
| Code | Action |
|---|---|
capability_expired | Retry with a smaller query. |
capability_unknown | Retry the query. Reopen the integration if the error continues. |
credential_failed | Make sure that authenticated endpoints use HTTPS and credentials are valid. |
dynamic_route_budget_exceeded | Narrow the query, or configure fewer vended storage prefixes. |
header_denied | Remove the unsupported header, or use the sandbox runtime. |
invalid_capability | Edit and re-save the integration. Contact an administrator if the error repeats. |
invalid_request | Make sure that the remote URL and headers are valid. |
method_denied | Use a GET or HEAD read, or use the sandbox runtime. |
object_changed | Retry against an immutable versioned DuckDB URL. |
range_invalid | Configure the database server to return valid single byte ranges. |
redirect_denied | Configure the DuckDB integration with the final exact object URL. |
redirect_budget_exceeded | Make sure that the integration endpoint is correct. |
request_budget_exceeded | Narrow the query, or split it into smaller queries. |
response_budget_exceeded | Select fewer columns or rows. |
strong_etag_required | Configure the database server to return a strong ETag. |
target_denied | Make sure that catalog redirects and broker_read_locations are correct. |
transport_failed | Make sure that DNS, TLS, and the integration egress policy permit the endpoint. |
Scope and caching
The browse API resolves an ID in the project tier before the organization tier. An organization integration is available from each project that inherits it. A project integration with the same name shadows the organization integration.
Each request checks whether the integration is available before it reads the cache. Disabling or shadowing an integration therefore takes effect immediately. A new configuration version uses a new cache entry.
Each replica can cache namespace and table lists for one minute and object-store root/object lists for 15 seconds. It can cache table schemas for five minutes. Searches, previews, tags, versions, content, failures, and authorization denials are not cached. Browse requests have per-user rate limits. The Refresh action bypasses the response cache, but it still uses the rate limit.
Using an integration in a notebook
Each kind documents its sandbox contract — the env vars and files it renders — in its section below and in the add-integration form. <NAME> is the integration's instance name upper-cased with - → _ (prod → PROD).
Every session also gets MARIMOHUB_INTEGRATIONS_DIR (default /tmp/marimohub-integrations) containing each integration's rendered files and a manifest.json naming the instances, kinds, and config versions in play. The directory sits outside the workspace, so rendered config is never captured back into the notebook's files.
Each kind declares the Python packages its contract assumes (Notebook packages below, echoed into manifest.json). Add them to the notebook's dependencies like any other package — the hub injects connection config, not Python libraries.
In the configuration references below, fields are shown as dotted paths into the config; field: value sub-tables list the extra fields available when a selector takes that value.
Connection variables and descriptors
Most kinds render one variable per connection field, named MARIMOHUB_<TOOL>_<NAME>_<FIELD> (for example MARIMOHUB_MYSQL_PROD_URL), alongside a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/<tool>/<name>.json that mirrors the same fields. A secret is never written into the descriptor: it appears there as <field>_env, naming the variable that holds it. Notebook code can therefore read the shape of a connection from one file without that file carrying a credential.
Vendor-standard variables and one-click connections
Some kinds also set the variable names their ecosystem already expects, under the ambient_env switch. There are two reasons to do that:
- Object stores and ML platforms are reached through libraries that read those variables and take no connection argument —
duckdbandpolarsexpectAWS_ACCESS_KEY_ID,wandbexpectsWANDB_API_KEY. These default on; Weights & Biases and Hugging Face have no other channel, so they always set them. - Databases and engines also hand notebook code an explicit URL or descriptor, but their discovery variables default on. This makes a compatible integration show up as a one-click connection in marimo's data-source panel with no code to copy.
| Kind | What marimo looks for |
|---|---|
| PostgreSQL | PGHOST, PGUSER, PGDATABASE — also PGPORT, PGPASSWORD, PGSSLMODE, PGSSLROOTCERT |
| MySQL | MYSQL_HOST, MYSQL_USER, MYSQL_DATABASE, MYSQL_PASSWORD — also MYSQL_TCP_PORT |
| Trino | TRINO_HOST, TRINO_USER, TRINO_CATALOG — also TRINO_PORT, TRINO_PASSWORD, TRINO_SCHEMA |
| PySpark | SPARK_REMOTE |
| S3 | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY — plus region and endpoint. On by default |
| Iceberg catalogs | the rendered .pyiceberg.yaml, found through PYICEBERG_HOME. Always set |
Because these names are process-wide, only one integration per session can claim a discovery contract. When multiple integrations request the same names, the first by integration name is discovered. The others remain available through their namespaced variables and notebook snippets. The session manifest and provisioning log contain a warning naming the selected and skipped integrations. When workload identity federation is enabled it injects AWS_* for the session's own bucket, and hub-injected variables win over integrations.
Two combinations fall back to the namespaced connection instead of advertising a connection that is weaker than the one you configured:
- MySQL with TLS on. The discovered connection is a PyMySQL URL with no TLS arguments, and PyMySQL reads none from the environment, so it would be a plaintext path to a server this integration requires TLS for.
- Trino with anything but Basic-over-HTTPS or no-auth-over-HTTP. Discovery cannot express JWT, OAuth2, Kerberos, or certificate authentication, so the suggested connection could not authenticate.
These fallbacks do not block session creation and emit a provisioning warning. PostgreSQL has no such caveat: libpq reads PGSSLMODE and PGSSLROOTCERT for any parameter the caller leaves unset, so a discovered connection verifies exactly like the rendered URL.
PostgreSQL
The sandbox gets MARIMOHUB_PG_<NAME>_URL (a SQLAlchemy-ready postgresql://… URL) plus _HOST/_PORT/_DATABASE/_USER/_PASSWORD, and a secret-free descriptor at $MARIMOHUB_INTEGRATIONS_DIR/postgres/<name>.json.
import os
import sqlalchemy
engine = sqlalchemy.create_engine(os.environ["MARIMOHUB_PG_PROD_URL"])TLS and certificates
New PostgreSQL integrations default to libpq's verify-full, which checks both the certificate chain and the hostname. libpq does not consult the system trust store on its own — with no sslrootcert it looks for ~/.postgresql/root.crt and fails when that file is absent — so the rendered URL points sslrootcert at the sandbox image's CA bundle (/etc/ssl/certs/ca-certificates.crt). A publicly trusted server therefore verifies with no extra setup. require encrypts but authenticates nothing — choose it deliberately.
That default path is correct for the Debian-based images built here. Two ways to point it elsewhere:
- CA path — an absolute path to a bundle the runtime already ships. Use it when a custom image keeps its bundle somewhere else (RHEL/UBI:
/etc/pki/tls/certs/ca-bundle.crt), or under the host-basedlocalcompute backend, where the image's path does not exist. - CA bundle — paste a private CA's PEM. It is written beside the integration's other files and
sslrootcertpoints there.
Set one or the other, not both.
Test connection opens a guarded native PostgreSQL connection, authenticates with the configured credentials, applies the selected TLS policy, and runs a read-only SELECT 1. It is available when MARIMOHUB_INTEGRATIONS_PROBE is guarded or private, independently of the data-browser rollout. Testing disable, prefer, or require also requires MARIMOHUB_POSTGRES_ALLOW_INSECURE_TRANSPORT=on.
Hub data browser
Direct PostgreSQL browsing is off by default. Enable it for all compatible PostgreSQL integrations:
MARIMOHUB_POSTGRES_DATA_ACCESS=onThe default metadata mode lists user schemas, selectable relations, and columns. Full mode also enables row previews and PostgreSQL-native Run SQL:
MARIMOHUB_DATA_BROWSER=fullThe Node server starts one worker and one database connection for each operation. It resolves the configured host through MARIMOHUB_INTEGRATIONS_PROBE, pins the approved addresses, and keeps the configured host for TLS SNI and hostname verification. guarded permits public targets. private also permits trusted private and loopback services. Cloudflare Workers do not install this runtime.
The hub supports verify-ca and verify-full when only the data-access switch is on. The disable, prefer, and require modes need this separate deployment override:
MARIMOHUB_POSTGRES_ALLOW_INSECURE_TRANSPORT=onFor hub access, paste a private CA into CA bundle. A custom CA path remains available to the notebook sandbox, but the hub cannot read sandbox image paths. Without a pasted bundle, the hub uses Node's default trust roots. This works across supported Node platforms and does not depend on a Linux distribution's CA path.
Run SQL uses PostgreSQL syntax. It runs one row-producing statement inside a read-only transaction with statement, lock, idle-transaction, row, byte, and wall-clock limits. Cancellation sends a PostgreSQL cancel request through a separately pinned socket. For TLS sessions, the cancel socket uses the same encryption, CA, and hostname-verification policy before it sends the backend cancel key, as supported by the PostgreSQL protocol. The cancel request is plaintext only for disable or when prefer falls back to plaintext.
PostgreSQL read-only transactions do not prevent every effect from a volatile user-defined function. Create a dedicated role with only the required CONNECT, schema USAGE, and table or view SELECT privileges. Do not grant write privileges or broad function execution rights to the production browser role.
For an emergency rollback, set MARIMOHUB_POSTGRES_DATA_ACCESS=off. Then restart the server. This change does not disable other data browsers. Existing notebook PostgreSQL connections remain available.
The runtime emits postgres_runtime.operation counters and postgres_runtime.duration_ms histograms. Labels contain only the operation and fixed outcome. Target policy, authentication, TLS, connection, timeout, malformed-result, and worker failures use fixed messages. A rejected SQL statement can also return its five-character SQLSTATE and a character position adjusted to the submitted statement. It never returns PostgreSQL's provider message. Check the data-browser mode, egress policy, role grants, TLS mode, and CA bundle for failures. The runtime does not log SQL, hostnames, database names, relation names, credentials, or provider error bodies.
By default, ambient_env also exports PGHOST, PGUSER, PGDATABASE, PGPORT, PGPASSWORD, and the TLS pair, which makes this connection discoverable in the notebook. Turn it off to expose only the namespaced connection.
postgres · database · config schema v2 · connection test supported
Notebook packages: sqlalchemy>=2, psycopg2-binary>=2.9
PostgreSQL configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Server hostname, e.g. db.internal | |
port | integer | 5432 | ||
database | string | Yes | ||
username | string | Yes | ||
password 🔒 | string | Yes | Password for the database user | |
ssl.mode | disable, prefer, require, verify-ca, verify-full | verify-full | libpq sslmode; verify-full checks the CA chain and the hostname | |
ambient_env | boolean | true | Automatically offer this connection in marimo's data-source discovery by exporting PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD, and PGSSLMODE. If multiple integrations request the same variables, one is discovered and every connection remains available through its notebook snippet. |
ssl.mode: verify-ca
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ssl.ca_bundle | string | PEM CA bundle to trust, written into the session | ||
ssl.ca_path | string | Absolute path to a CA bundle the runtime already ships (default /etc/ssl/certs/ca-certificates.crt) |
ssl.mode: verify-full
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ssl.ca_bundle | string | PEM CA bundle to trust, written into the session | ||
ssl.ca_path | string | Absolute path to a CA bundle the runtime already ships (default /etc/ssl/certs/ca-certificates.crt) |
MySQL
The sandbox gets MARIMOHUB_MYSQL_<NAME>_URL (a mysql+pymysql:// URL) plus _HOST/_PORT/_DATABASE/_USER/_PASSWORD, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/mysql/<name>.json. Works with MariaDB too.
New connections verify TLS: the rendered URL names a CA bundle, which makes PyMySQL check both the chain and the hostname. Paste a private CA as CA bundle, or point CA path at one the image already ships. The intermediate MySQL modes are deliberately absent — they are spelled with boolean-ish URL arguments whose meaning depends on how a driver version coerces the string "false", so the choice here is verified TLS or none.
ambient_env requests the MYSQL_* names for discovery. They are emitted only when TLS is disabled; otherwise the namespaced TLS connection stays available and the provisioning log explains the fallback.
mysql · database · config schema v1
Notebook packages: sqlalchemy>=2, pymysql>=1.1
MySQL configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Server hostname, e.g. mysql.internal | |
port | integer | 3306 | ||
database | string | Yes | ||
username | string | Yes | ||
password 🔒 | string | Yes | Password for the database user | |
ssl.mode | verify_identity, disabled | verify_identity | verify_identity checks the CA chain and the hostname; disabled is plaintext | |
ambient_env | boolean | true | Automatically offer this connection in marimo's data-source discovery by exporting MYSQL_HOST, MYSQL_TCP_PORT, MYSQL_DATABASE, MYSQL_USER, and MYSQL_PASSWORD. If multiple integrations request the same variables, one is discovered and every connection remains available through its notebook snippet. |
ssl.mode: verify_identity
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ssl.ca_bundle | string | PEM CA bundle to trust, written into the session | ||
ssl.ca_path | string | Absolute path to a CA bundle the runtime already ships (default /etc/ssl/certs/ca-certificates.crt) |
Microsoft SQL Server
The sandbox gets MARIMOHUB_MSSQL_<NAME>_URL plus the usual connection variables and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/sqlserver/<name>.json.
Pick the driver your image has. pyodbc (default) encrypts and verifies by default and needs the named ODBC driver installed in the sandbox image; pymssql needs no system driver but leaves encryption to FreeTDS negotiation, so it cannot enforce it.
sqlserver · database · config schema v1
Notebook packages: sqlalchemy>=2, pyodbc>=5.1, pymssql>=2.3
Microsoft SQL Server configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Server hostname, e.g. mssql.internal | |
port | integer | 1433 | ||
database | string | Yes | ||
username | string | Yes | ||
password 🔒 | string | Yes | Password for the database user | |
driver.name | pyodbc, pymssql | pyodbc |
driver.name: pyodbc
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
driver.odbc_driver | string | ODBC Driver 18 for SQL Server | Must be installed in the sandbox image | |
driver.encrypt | boolean | true | ||
driver.trust_server_certificate | boolean | false | Accept any server certificate — encrypts without authenticating |
MongoDB
The sandbox gets MARIMOHUB_MONGODB_<NAME>_URL for pymongo.MongoClient, plus _HOST/_DATABASE/_USER/_PASSWORD and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/mongodb/<name>.json.
mongodb+srv (the default) resolves the replica-set members from DNS, which is how Atlas and most managed deployments are addressed; it ignores the port. A literal seed list of several members is not supported — use SRV, or point at one member with the mongodb scheme.
mongodb · database · config schema v1
Notebook packages: pymongo>=4.9
MongoDB configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
scheme | mongodb+srv, mongodb | mongodb+srv | ||
host | string | Yes | Cluster hostname, e.g. cluster0.abcde.mongodb.net | |
port | integer | 27017 | Ignored for mongodb+srv | |
database | string | Default database for client.get_database() | ||
auth.method | password, none | none | ||
tls.mode | enabled, disabled | enabled |
auth.method: password
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.username | string | Yes | ||
auth.password 🔒 | string | Yes | ||
auth.auth_source | string | admin |
tls.mode: enabled
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
tls.ca_bundle | string | PEM CA bundle to trust, written into the session | ||
tls.ca_path | string | Absolute path to a CA bundle the runtime already ships (default /etc/ssl/certs/ca-certificates.crt) |
ClickHouse
The sandbox gets MARIMOHUB_CLICKHOUSE_<NAME>_HOST/_PORT/_SECURE/_DATABASE/_USER/_PASSWORD for clickhouse_connect.get_client(), a clickhouse+http:// URL for SQLAlchemy, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/clickhouse/<name>.json. Test probes the HTTP interface with SELECT version().
clickhouse · database · config schema v1 · connection test supported
Notebook packages: clickhouse-connect>=0.8
ClickHouse configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Server hostname, e.g. abc123.us-east-1.aws.clickhouse.cloud | |
port | integer | 8443 | HTTP interface port | |
secure | boolean | true | Use HTTPS for the HTTP interface | |
verify | boolean | true | Verify the server certificate (clickhouse-connect verify) | |
database | string | default | ||
username | string | default | ||
password 🔒 | string | Omit for a user with no password |
Snowflake
The sandbox gets MARIMOHUB_SNOWFLAKE_<NAME>_ACCOUNT/_USER/_WAREHOUSE/_DATABASE/_SCHEMA/_ROLE plus the credential for the chosen method, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/snowflake/<name>.json.
Password authentication also renders _URL for snowflake-sqlalchemy. A key pair cannot be expressed in a URL, so the PKCS#8 key is written beside the integration and _PRIVATE_KEY_PATH points at it — pass it to snowflake.connector.connect() instead of a URL.
snowflake · database · config schema v1
Notebook packages: snowflake-connector-python>=3.12, snowflake-sqlalchemy>=1.7
Snowflake configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
account | string | Yes | Account identifier, e.g. myorg-account1 | |
user | string | Yes | ||
auth.method | password, key_pair, oauth | Yes | ||
warehouse | string | Warehouse the session runs on | ||
database | string | Session default database | ||
schema | string | Session default schema | ||
role | string | Role the session assumes |
auth.method: password
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.password 🔒 | string | Yes |
auth.method: key_pair
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.private_key 🔒 | string | Yes | PKCS#8 private key PEM, written into the session | |
auth.private_key_passphrase 🔒 | string |
auth.method: oauth
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
BigQuery
The sandbox gets MARIMOHUB_BIGQUERY_<NAME>_URL (a bigquery:// URL for sqlalchemy-bigquery) plus _PROJECT_ID/_DATASET/_LOCATION, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/bigquery/<name>.json.
A service-account key is written to a file and referenced by path — the URL carries the path, never the key. ambient_env is off by default here, unlike the storage kinds: the URL already names the key file, so leaving GOOGLE_APPLICATION_CREDENTIALS to a GCS integration, whose client reads nothing else, keeps the two from colliding. Turn it on if you want bigquery.Client() with no arguments to work and no GCS integration is claiming it.
bigquery · database · config schema v1
Notebook packages: google-cloud-bigquery>=3.25, sqlalchemy-bigquery>=1.11
BigQuery configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
project_id | string | Yes | Google Cloud project that owns the datasets | |
dataset | string | Default dataset for unqualified table names | ||
location | string | Dataset location, e.g. US or europe-west4 | ||
auth.method | ambient, service_account | ambient | ||
ambient_env | boolean | false | Also export the vendor-standard variables so libraries pick this up with no configuration. Only one integration per session can claim them. |
auth.method: service_account
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.credentials_json 🔒 | string | Yes |
Amazon Redshift
The sandbox gets MARIMOHUB_REDSHIFT_<NAME>_URL (a redshift+redshift_connector:// URL) plus the usual connection variables and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/redshift/<name>.json.
Both offered SSL modes verify the chain against the driver's bundled Amazon trust store; verify-full also checks the hostname. Disabling TLS is not offered — the driver takes that as a real boolean, which a URL argument cannot carry unambiguously.
redshift · database · config schema v1
Notebook packages: sqlalchemy-redshift>=0.14, redshift-connector>=2.1
Amazon Redshift configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Cluster or workgroup endpoint, e.g. wg.123456789012.us-east-1.redshift-serverless.amazonaws.com | |
port | integer | 5439 | ||
database | string | Yes | ||
username | string | Yes | ||
password 🔒 | string | Yes | Password for the database user | |
ssl_mode | verify-ca, verify-full | verify-ca |
MotherDuck
The sandbox gets MARIMOHUB_MOTHERDUCK_<NAME>_URL, an md: connection string to hand to duckdb.connect(), plus _TOKEN and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/motherduck/<name>.json.
import duckdb
import os
con = duckdb.connect(os.environ["MARIMOHUB_MOTHERDUCK_PROD_URL"])DuckDB's own motherduck_token variable is lower-case, which the hub cannot emit (rendered names are POSIX-shell-safe upper-snake only), so the token rides in the connection string instead.
motherduck · database · config schema v1
Notebook packages: duckdb>=1.1
MotherDuck configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
token 🔒 | string | Yes | MotherDuck service token | |
database | string | Database to attach; omit to attach every database in the account | ||
saas_mode | boolean | false | Block local file and extension access from the MotherDuck session |
Iceberg catalogs
All Iceberg kinds are written into $MARIMOHUB_INTEGRATIONS_DIR/.pyiceberg.yaml; PYICEBERG_HOME points there, so pyiceberg.catalog.load_catalog("<name>") works directly:
from pyiceberg.catalog import load_catalog
catalog = load_catalog("prod")The typed storage selector (storage.scheme) covers catalog-provided credentials, S3/compatible stores, GCS, ADLS, HDFS, and Hugging Face. Process-wide worker/compatibility settings and PyArrow read behavior are also typed. Non-secret PyIceberg options that are not first-class fields remain available through extra_properties; credential-shaped keys are rejected there so secrets cannot bypass encryption.
PyIceberg's in-memory catalog is intentionally not an integration kind: the official documentation describes it as non-concurrent test/demo state, so it cannot serve as a reusable project data source. Custom catalog implementations and custom REST authentication managers are also excluded because accepting an arbitrary Python class path would turn configuration into code loading. A few PyIceberg settings apply to the whole process rather than one catalog; see the failure model for how conflicting values are handled.
Iceberg REST Catalog
Connects to an Iceberg REST catalog such as Polaris, Unity, Gravitino, or Glue. Supports no auth, bearer tokens, Basic, OAuth2 client credentials, AWS SigV4, Google ADC/service accounts, and Entra; REST/TLS tuning; access delegation; and the documented remote FileIO families.
iceberg_rest · catalog · config schema v3 · connection test supported
Notebook packages: pyiceberg[pyarrow,s3fs,gcsfs,adlfs,hf,rest-sigv4,gcp-auth,entra-auth]>=0.11
Iceberg REST Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
uri | string | Yes | REST catalog base URI, e.g. https://catalog.internal/api/catalog | |
warehouse | string | Warehouse name/path if the server hosts several | ||
allow_insecure_transport | boolean | false | Allow http:// endpoints to carry credentials — local development only | |
auth.method | none, bearer_token, basic, oauth2_client_credentials, sigv4, google, entra | Yes | ||
storage | ||||
runtime | ||||
access_delegation | none, vended_credentials, remote_signing, both | vended_credentials | Catalog delegation mode. Guarded Run SQL supports bounded S3 vended credentials. | |
tls.ca_bundle | string | |||
tls.client_certificate | string | |||
tls.client_key 🔒 | string | |||
rest.snapshot_loading_mode | all, refs | all | ||
rest.metrics_reporting_enabled | boolean | true | ||
rest.page_size | integer | |||
rest.view_endpoints_supported | boolean | false | ||
rest.scan_planning_mode | client, server | client | ||
rest.namespace_separator | string | %1F | ||
rest.table_cache_expire_after_write_ms | integer | 300000 | ||
rest.table_cache_max_entries | integer | 100 | ||
headers | map<string, string> | Additional HTTP headers sent to the REST catalog | ||
extra_properties |
auth.method: bearer_token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
auth.method: basic
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.username | string | Yes | ||
auth.password 🔒 | string | Yes |
auth.method: oauth2_client_credentials
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token_endpoint | string | Yes | ||
auth.client_id | string | Yes | ||
auth.client_secret 🔒 | string | Yes | ||
auth.scope | string | catalog | ||
auth.refresh_margin_seconds | integer | 60 | ||
auth.expires_in_seconds | integer |
auth.method: sigv4
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.region | string | Yes | ||
auth.signing_name | string | execute-api |
auth.method: google
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.scopes | string | Comma-separated OAuth scopes; uses Google ADC | ||
auth.credentials_json 🔒 | string | Google service-account JSON |
auth.method: entra
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.scopes | string | Comma-separated OAuth scopes; uses Azure credentials | ||
auth.managed_identity_client_id | string |
Iceberg SQL Catalog
Stores catalog metadata in PostgreSQL or SQLite, with SQLAlchemy initialization, liveness, and logging options. The SQLAlchemy URI is encrypted because it commonly embeds credentials.
iceberg_sql · catalog · config schema v1
Notebook packages: pyiceberg[pyarrow,sql-postgres,sql-sqlite,s3fs,gcsfs,adlfs,hf]>=0.11
Iceberg SQL Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
uri 🔒 | string | Yes | SQLAlchemy URI for PostgreSQL or SQLite | |
warehouse | string | Default Iceberg table storage location | ||
init_catalog_tables | boolean | true | ||
echo | boolean | false | ||
pool_pre_ping | boolean | false | ||
storage | ||||
runtime | ||||
extra_properties |
Iceberg Hive Catalog
Connects PyIceberg to a Hive Metastore over Thrift, with Hive 2 compatibility, Kerberos, and UGI options.
iceberg_hive · catalog · config schema v1
Notebook packages: pyiceberg[pyarrow,hive,hive-kerberos,s3fs,gcsfs,adlfs,hf]>=0.11
Iceberg Hive Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
uri | string | Yes | ||
warehouse | string | Default Iceberg table storage location | ||
hive2_compatible | boolean | false | ||
kerberos.enabled | boolean | false | ||
kerberos.service_name | string | hive | ||
ugi 🔒 | string | Hadoop user/group identity | ||
storage | ||||
runtime | ||||
extra_properties |
Iceberg AWS Glue Catalog
Uses AWS Glue as the metastore, with catalog/account/endpoint/retry configuration and ambient, profile, encrypted static, or shared catalog/FileIO AWS credentials.
iceberg_glue · catalog · config schema v1
Notebook packages: pyiceberg[pyarrow,glue,s3fs,gcsfs,adlfs,hf]>=0.11
Iceberg AWS Glue Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
warehouse | string | Default Iceberg table storage location | ||
catalog_id | string | |||
region | string | |||
endpoint | string | |||
credentials.method | ambient, static, profile | ambient | Glue Catalog credentials only. When explicit, these override unified credentials for Glue calls. The catalog region uses the region field; PyIceberg exposes role assumption through unified credentials. | |
unified_credentials.method | none, static, profile, role | none | Client credentials shared by Glue and S3 FileIO. Glue-specific and storage-specific credentials override these. | |
skip_archive | boolean | true | ||
max_retries | integer | 10 | ||
retry_mode | legacy, standard, adaptive | standard | ||
storage | ||||
runtime | ||||
extra_properties |
credentials.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
credentials.access_key_id 🔒 | string | Yes | ||
credentials.secret_access_key 🔒 | string | Yes | ||
credentials.session_token 🔒 | string |
credentials.method: profile
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
credentials.profile_name | string | Yes |
unified_credentials.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.access_key_id 🔒 | string | Yes | ||
unified_credentials.secret_access_key 🔒 | string | Yes | ||
unified_credentials.session_token 🔒 | string |
unified_credentials.method: profile
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.profile_name | string | Yes |
unified_credentials.method: role
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.role_arn | string | Yes | ||
unified_credentials.role_session_name | string |
Iceberg DynamoDB Catalog
Uses an AWS DynamoDB table as the catalog, with the same ambient, profile, encrypted static, or shared catalog/FileIO AWS credential choices.
iceberg_dynamodb · catalog · config schema v1
Notebook packages: pyiceberg[pyarrow,dynamodb,s3fs,gcsfs,adlfs,hf]>=0.11
Iceberg DynamoDB Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
table_name | string | iceberg | ||
warehouse | string | Default Iceberg table storage location | ||
region | string | |||
credentials.method | ambient, static, profile | ambient | DynamoDB Catalog credentials only. When explicit, these override unified credentials for DynamoDB calls. The catalog region uses the region field; PyIceberg exposes role assumption through unified credentials. | |
unified_credentials.method | none, static, profile, role | none | Client credentials shared by DynamoDB and S3 FileIO. DynamoDB-specific and storage-specific credentials override these. | |
storage | ||||
runtime | ||||
extra_properties |
credentials.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
credentials.access_key_id 🔒 | string | Yes | ||
credentials.secret_access_key 🔒 | string | Yes | ||
credentials.session_token 🔒 | string |
credentials.method: profile
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
credentials.profile_name | string | Yes |
unified_credentials.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.access_key_id 🔒 | string | Yes | ||
unified_credentials.secret_access_key 🔒 | string | Yes | ||
unified_credentials.session_token 🔒 | string |
unified_credentials.method: profile
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.profile_name | string | Yes |
unified_credentials.method: role
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
unified_credentials.region | string | |||
unified_credentials.role_arn | string | Yes | ||
unified_credentials.role_session_name | string |
Iceberg BigQuery Metastore
Uses Google BigQuery as the metastore, with ADC or encrypted service-account JSON and independent FileIO configuration. BigQuery requires legacy-current-snapshot-id, so it cannot share a project with a catalog that disables it (see the failure model).
iceberg_bigquery · catalog · config schema v1
Notebook packages: pyiceberg[pyarrow,bigquery,gcsfs,s3fs,adlfs,hf]>=0.11
Iceberg BigQuery Metastore Catalog configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
project_id | string | Yes | ||
location | string | |||
warehouse | string | Yes | Default Iceberg table storage location | |
credentials.method | ambient, service_account_json | ambient | ||
storage | ||||
runtime | ||||
extra_properties |
credentials.method: service_account_json
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
credentials.credentials_json 🔒 | string | Yes |
Trino
The sandbox gets MARIMOHUB_TRINO_<NAME>_URL plus connection env vars and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/trino/<name>.json. Supports Basic, JWT, OAuth2, client certificates, Kerberos, GSSAPI, TLS verification, headers, extra credentials, roles, session properties, spooling, retries, timeouts, isolation, and compatibility options.
By default, ambient_env exports TRINO_HOST, TRINO_USER, TRINO_CATALOG, and the rest for discovery. It needs a default catalog, system TLS verification, and an authentication mode discovery can express. Other configurations keep the namespaced connection and emit a provisioning warning.
trino · engine · config schema v1 · connection test supported
Notebook packages: trino[sqlalchemy,kerberos,gssapi]>=0.330
Trino configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Coordinator hostname, e.g. trino.internal | |
port | integer | 443 | ||
http_scheme | https, http | https | ||
user | string | Query user; defaults to the signed-in user | ||
auth.method | none, basic, jwt, oauth2, certificate, kerberos, gssapi | Yes | ||
tls.verification | system, disabled, custom_ca | system | ||
default_catalog | string | Default catalog; required for automatic marimo data-source discovery | ||
default_schema | string | |||
source | string | |||
session_properties | map<string, string> | |||
roles | map<string, string> | |||
client_tags | object[] | |||
client_tags[].value | string | Yes | ||
http_headers | object[] | |||
http_headers[].name | string | Yes | ||
http_headers[].value 🔒 | string | Yes | ||
extra_credentials | object[] | |||
extra_credentials[].name | string | Yes | ||
extra_credentials[].value 🔒 | string | Yes | ||
timezone | string | |||
encoding | object[] | |||
encoding[].value | json, json+lz4, json+zstd | Yes | ||
max_attempts | integer | |||
request_timeout_seconds | number | |||
heartbeat_interval_seconds | number | |||
isolation_level | AUTOCOMMIT, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE | AUTOCOMMIT | ||
legacy_primitive_types | boolean | false | ||
legacy_prepared_statements | boolean | |||
ambient_env | boolean | true | Automatically offer this connection in marimo's data-source discovery by exporting TRINO_HOST, TRINO_PORT, TRINO_USER, TRINO_CATALOG, and TRINO_PASSWORD. If multiple integrations request the same variables, one is discovered and every connection remains available through its notebook snippet. |
auth.method: basic
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.username | string | Yes | ||
auth.password 🔒 | string | Yes |
auth.method: jwt
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
auth.method: certificate
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.client_certificate | string | Yes | ||
auth.client_key 🔒 | string | Yes |
auth.method: kerberos
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.krb5_config | string | |||
auth.service_name | string | |||
auth.mutual_authentication | required, optional, disabled | required | ||
auth.force_preemptive | boolean | false | ||
auth.hostname_override | string | |||
auth.sanitize_mutual_error_response | boolean | true | ||
auth.principal | string | |||
auth.delegate | boolean | false |
auth.method: gssapi
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.krb5_config | string | |||
auth.service_name | string | |||
auth.mutual_authentication | required, optional, disabled | disabled | ||
auth.force_preemptive | boolean | false | ||
auth.hostname_override | string | |||
auth.sanitize_mutual_error_response | boolean | true | ||
auth.principal | string | |||
auth.delegate | boolean | false |
tls.verification: custom_ca
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
tls.ca_bundle | string | Yes |
PySpark (Spark Connect)
The sandbox gets MARIMOHUB_PYSPARK_<NAME>_REMOTE, optional _TOKEN, and pyspark/<name>.json with the SparkSession settings. Supports token auth, user identity, gRPC keepalive/metadata, and plain or encrypted Spark configuration.
Pass the named remote URL to SparkSession.builder.remote(), then apply the settings from the JSON descriptor before calling getOrCreate(). This integration targets Spark Connect. Provisioning a classic Spark driver or cluster remains the compute backend's responsibility.
By default, ambient_env also exports the same string as SPARK_REMOTE, which SparkSession.builder reads on its own and marimo discovers — so getOrCreate() needs no arguments at all.
Test verifies DNS, TCP reachability, and the TLS handshake when enabled. It does not create a Spark session or validate authentication and Spark configuration.
pyspark · engine · config schema v1 · connection test supported
Notebook packages: pyspark[connect]>=4.2
PySpark (Spark Connect) configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | ||
port | integer | 15002 | ||
use_ssl | boolean | true | ||
auth.method | none, token | none | ||
user_id | string | |||
user_agent | string | |||
app_name | string | |||
keepalive.enabled | boolean | true | ||
keepalive.time_ms | integer | 60000 | ||
keepalive.timeout_ms | integer | 20000 | ||
keepalive.without_calls | boolean | true | ||
metadata | object[] | |||
metadata[].name | string | Yes | ||
metadata[].value 🔒 | string | Yes | ||
spark_config | map<string, string> | |||
secret_spark_config | object[] | |||
secret_spark_config[].name | string | Yes | ||
secret_spark_config[].value 🔒 | string | Yes | ||
ambient_env | boolean | true | Automatically offer this connection in marimo's data-source discovery by exporting SPARK_REMOTE. If multiple integrations request the same variables, one is discovered and every connection remains available through its notebook snippet. |
auth.method: token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
Databricks SQL
The sandbox gets MARIMOHUB_DATABRICKS_<NAME>_HOST/_HTTP_PATH/_CATALOG/_SCHEMA for databricks.sql.connect(), plus the credential for the chosen method and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/databricks/<name>.json. Personal access tokens also render _URL for databricks-sqlalchemy; an OAuth service principal cannot be expressed in a URL, so it renders _CLIENT_ID and _CLIENT_SECRET instead. Test calls the workspace SCIM identity endpoint.
databricks · engine · config schema v1 · connection test supported
Notebook packages: databricks-sql-connector>=3.4, databricks-sqlalchemy>=1.0
Databricks SQL configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
host | string | Yes | Workspace hostname, e.g. dbc-1234abcd-5678.cloud.databricks.com | |
http_path | string | Yes | SQL warehouse or cluster HTTP path | |
auth.method | personal_access_token, oauth_m2m | Yes | ||
catalog | string | Unity Catalog name for unqualified tables | ||
schema | string | Session default schema |
auth.method: personal_access_token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.token 🔒 | string | Yes |
auth.method: oauth_m2m
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.client_id | string | Yes | ||
auth.client_secret 🔒 | string | Yes |
Amazon Athena
The sandbox gets MARIMOHUB_ATHENA_<NAME>_URL for PyAthena's SQLAlchemy dialect, plus _REGION/_DATABASE/_WORKGROUP/_CATALOG/_S3_STAGING_DIR and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/athena/<name>.json. Athena writes query results to the staging prefix, so the credentials need write access to it.
With ambient credentials the URL keeps PyAthena's empty userinfo (://:@), which is what makes the driver fall through to boto3's provider chain — an instance profile, or an S3 integration that claims the ambient AWS variables.
athena · engine · config schema v1
Notebook packages: pyathena[sqlalchemy]>=3.9
Amazon Athena configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
region | string | Yes | ||
s3_staging_dir | string | Yes | Bucket prefix Athena writes query results to | |
database | string | default | ||
workgroup | string | primary | ||
catalog | string | AwsDataCatalog | ||
auth.method | ambient, static | ambient |
auth.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.access_key_id 🔒 | string | Yes | ||
auth.secret_access_key 🔒 | string | Yes | ||
auth.session_token 🔒 | string |
Object storage
These kinds carry no query engine. They configure the credentials that duckdb, polars, pandas, and the fsspec family use to read objects directly, and they are how an Iceberg or Athena setup gets access to the data files behind its metadata. See vendor-standard variables for what ambient_env claims and how collisions are reported.
S3
The sandbox gets MARIMOHUB_S3_<NAME>_BUCKET/_REGION/_ENDPOINT_URL/_ADDRESSING_STYLE plus static credentials when configured, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/s3/<name>.json. With ambient_env on it also sets AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGION, AWS_DEFAULT_REGION, and AWS_ENDPOINT_URL_S3.
The endpoint is S3-scoped on purpose: the unscoped AWS_ENDPOINT_URL would point STS and every other AWS service at the same store. Path-style addressing has no variable of its own — boto3 reads it from a config file — so choosing it also renders one and sets AWS_CONFIG_FILE, which replaces any other profile file the image ships.
Works with MinIO, Cloudflare R2, Ceph, and other S3-compatible stores: set the endpoint and, for most of them, path-style addressing.
Run SQL requires an explicit endpoint, static credentials or anonymous access, and a guarded read location. Each location grants one bucket prefix. The default bucket does not grant access. Static credentials require HTTPS by default. Enable allow_insecure_transport only for local development. Anonymous endpoints can use HTTP without this option.
Upgrade note: Stored authenticated HTTP S3 configurations keep their current behavior. The schema migration enables
allow_insecure_transportfor those configurations. New configurations must enable this option explicitly.
Use exact Parquet or CSV object paths. Globs are unavailable because they require a broader S3 list request. JSON is unavailable until the DuckDB-Wasm package includes the signed json extension. The broker permits only GET and HEAD, so queries cannot write objects.
s3 · storage · config schema v2 · connection test supported
Notebook packages: boto3>=1.35, s3fs>=2024.6
S3 object storage configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
bucket | string | Default bucket for notebook code; the credentials are not restricted to it | ||
region | string | Region name, e.g. us-east-1 | ||
endpoint_url | string | S3-compatible endpoint, e.g. https://minio.internal:9000; omit for AWS S3 | ||
allow_insecure_transport | boolean | false | Allow http:// endpoints to carry credentials — local development only | |
auth.method | ambient, static, anonymous | ambient | ||
path_style | boolean | false | Address buckets as endpoint/bucket, which most S3-compatible stores require | |
broker_read_locations | object[] | S3 bucket prefixes the guarded DuckDB broker may read | ||
broker_read_locations[].bucket | string | Yes | ||
broker_read_locations[].prefix | string | Yes | ||
ambient_env | boolean | true | Also export the vendor-standard variables so libraries pick this up with no configuration. Only one integration per session can claim them. |
auth.method: static
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.access_key_id 🔒 | string | Yes | ||
auth.secret_access_key 🔒 | string | Yes | ||
auth.session_token 🔒 | string |
Google Cloud Storage
The sandbox gets MARIMOHUB_GCS_<NAME>_BUCKET/_PROJECT_ID/_CREDENTIALS_PATH and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/gcs/<name>.json. A service-account key is written to a file; with ambient_env on, GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_CLOUD_PROJECT point at it, which is what gcsfs and google-cloud-storage read.
gcs · storage · config schema v1 · connection test supported
Notebook packages: gcsfs>=2024.6, google-cloud-storage>=2.18
Google Cloud Storage configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
bucket | string | Default bucket for notebook code; the credentials are not restricted to it | ||
project_id | string | Project billed for the requests | ||
auth.method | ambient, service_account | ambient | ||
ambient_env | boolean | true | Also export the vendor-standard variables so libraries pick this up with no configuration. Only one integration per session can claim them. |
auth.method: service_account
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.credentials_json 🔒 | string | Yes |
Azure Blob Storage
The sandbox gets MARIMOHUB_AZURE_<NAME>_ACCOUNT_NAME/_ACCOUNT_URL/_CONTAINER plus the credential for the chosen method, and a descriptor at $MARIMOHUB_INTEGRATIONS_DIR/azure/<name>.json. With ambient_env on it sets the AZURE_STORAGE_* names adlfs reads, and a service principal's AZURE_TENANT_ID/AZURE_CLIENT_ID/AZURE_CLIENT_SECRET for DefaultAzureCredential.
azure_blob · storage · config schema v1 · connection test supported
Notebook packages: adlfs>=2024.7, azure-storage-blob>=12.22, azure-identity>=1.17
Azure Blob Storage configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
account_name | string | Yes | ||
container | string | Default container for notebook code | ||
endpoint_suffix | string | core.windows.net | Sovereign clouds use their own, e.g. core.chinacloudapi.cn | |
auth.method | ambient, account_key, sas_token, connection_string, service_principal | Yes | ||
ambient_env | boolean | true | Also export the vendor-standard variables so libraries pick this up with no configuration. Only one integration per session can claim them. |
auth.method: account_key
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.account_key 🔒 | string | Yes |
auth.method: sas_token
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.sas_token 🔒 | string | Yes |
auth.method: connection_string
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.connection_string 🔒 | string | Yes |
auth.method: service_principal
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
auth.tenant_id | string | Yes | ||
auth.client_id | string | Yes | ||
auth.client_secret 🔒 | string | Yes |
Weights & Biases
Sets WANDB_API_KEY, WANDB_BASE_URL, WANDB_ENTITY, WANDB_PROJECT, and WANDB_MODE, so wandb.init() needs no wandb.login() and no key in the notebook. WANDB_DIR points run files at /tmp, outside the workspace, so they are not captured into a notebook version. Test authenticates against the GraphQL API.
Because the client only reads these standard names, one project can have one active Weights & Biases integration.
wandb · other · config schema v1 · connection test supported
Notebook packages: wandb>=0.18
Weights & Biases configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
api_key 🔒 | string | Yes | API key from wandb.ai/authorize | |
base_url | string | https://api.wandb.ai | Set this for a self-hosted or dedicated-cloud deployment | |
entity | string | Default team or user | ||
project | string | |||
mode | online, offline | online | offline records runs to disk without contacting the server |
Hugging Face
Sets HF_TOKEN and HF_ENDPOINT, which authenticates huggingface_hub, transformers, and datasets for gated models and private repositories. HF_HOME points the model cache at /tmp, outside the workspace — model weights are large and must not be captured into a notebook version. Test calls /api/whoami-v2.
As with Weights & Biases, the client reads only these standard names, so one project can have one active Hugging Face integration.
huggingface · other · config schema v1 · connection test supported
Notebook packages: huggingface-hub>=0.25
Hugging Face configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
token 🔒 | string | Yes | Access token from huggingface.co/settings/tokens | |
endpoint | string | https://huggingface.co | Set this for an Enterprise Hub deployment | |
enable_hf_transfer | boolean | false | Faster large-file downloads; requires the hf_transfer package |
Environment variables
Adds the exact environment variables that you configure. It supports plain variables, secret variables, and secret JSON bundles with optional prefixes.
custom_env · other · config schema v1
Environment variables configuration reference
Fields marked 🔒 use an encrypted value or an external reference. API responses never contain the resolved value.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
vars | map<string, string> | Plain environment variables, visible to project managers | ||
secrets | object[] | Secret environment variables from encrypted values or an external manager | ||
secrets[].name | string | Yes | ||
secrets[].value 🔒 | string | Yes | ||
secret_bundles | object[] | JSON secret objects expanded into one environment variable per key | ||
secret_bundles[].name | string | Yes | Stable name used to retain this bundle across edits | |
secret_bundles[].value 🔒 | string | Yes | A JSON object containing environment variable values | |
secret_bundles[].prefix | string |
Managing integrations
Open a project and select Environment & cloud access. Then select Integrations. Members can view the list and protected configuration. Project managers and super admins can make changes.
- Add selects a kind and opens its schema-based form.
- Test connection runs against the current draft for supported kinds. It includes edited references and unchanged inline values.
- Edit appends an immutable configuration version. List versions at
GET …/integrations/{iid}/versions. - Enable or disable controls whether new sessions receive the integration. Disable a broken integration to restore session access.
- Delete removes the integration and its complete version history.
- Copy from another project copies the current version and starts at v1. You need manager access to both projects. Inline values get new encryption for the destination. External references remain unchanged.
Connection tests run from the server. The default egress policy permits only public targets. It blocks redirects and private, loopback, link-local, metadata, and CGNAT addresses. It also limits response size, duration, and request rate.
Set MARIMOHUB_INTEGRATIONS_PROBE=private for private targets. Set it to off to disable connection tests.
PostgreSQL connection tests open a native guarded socket instead of an HTTP probe. They use the same address policy, deadline, and request rate.
New sessions use configuration changes. Restart a running session to apply them.
Updates and concurrency
The API updates an integration as one resource. Each update submits the complete configuration and appends an immutable version.
For automation, read the integration ETag and send it as If-Match. If another client changed the integration, the server rejects the update.
Managed markers keep unchanged inline values. References include their complete backend and locator. See Integration secret sources for retention and testing rules.
Organization-wide integrations
A super admin can configure an integration once for the whole deployment. Use Org integrations in the user menu, or use the /api/v1/org/integrations API routes.
Each organization integration applies to every project. It supplies configuration to new, non-ephemeral sessions in those projects. The project integration list shows inherited entries with an org badge. These entries are read-only in the project. Users with viewer access can see their metadata, but not their configuration.
To override an organization integration, create a project integration with the same name. The project configuration then supplies new sessions in that project. To opt out instead, create the same-name project integration and leave it disabled. The list continues to show the inherited entry with an overridden badge.
An organization integration that fails to render blocks new sessions in each project that inherits it. See the failure model. To unblock one project, override the failing integration or opt out. To unblock all projects, disable the organization integration.
Configuration changes apply to new sessions. Running sessions keep their existing configuration.
Secret fields
Each secret field uses an inline encrypted value or an external reference. API reads return a marker for inline values or metadata for references. They never return a resolved value. See Integration secret sources for setup and API shapes.
Failure model
Integration rendering fails closed. A secret-source or configuration error stops session creation without disclosing secret values or locators.
Automatic data-source discovery is best effort. An incompatible discovery contract or a second integration claiming the same standard variables falls back to namespaced variables and a notebook snippet instead of failing the session. The session manifest and provisioning log record the fallback.
Saving a reference does not fetch its value. Test connection resolves the current draft for supported kinds. Environment variables has no connection test, so its resolution errors can first appear during session creation.
Environment-name precedence is integrations < hub, WIF, AI, and marimo configuration. An integration cannot replace a hub-controlled value.
A few PyIceberg settings (legacy-current-snapshot-id, max-workers) apply to the whole process, not to one catalog, so two Iceberg integrations in the same project must agree on them. They cannot be reconciled automatically — choosing one value would change how the other integration reads data — so a disagreement fails the session with an error naming both integrations and both values. Note that the BigQuery catalog requires legacy-current-snapshot-id, so it cannot share a project with a catalog that disables it. Align the values or disable one of the two.
Configuration
| Variable | Description |
|---|---|
MARIMOHUB_INTEGRATIONS | on (default) or off to disable routes and session injection. Replace the removed true/none aliases before upgrading. |
MARIMOHUB_INTEGRATIONS_PROBE | "Test connection" egress policy: guarded (default), private, off. |
MARIMOHUB_SECRETS_KEK | Enables inline encrypted integration secret fields. |
Developing integration kinds
For source layout, kind contracts, schema evolution, and tests, see the integration developer guide.