Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 50 additions & 26 deletions src/documentation/user_guides/publishing/connections.malloynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,30 @@ Configure database connections for Malloy Publisher deployments. For an overview

## Configuration File

Publisher uses `publisher.config.json` for database connections. This file lives in your server root directory.
Publisher uses `publisher.config.json` for database connections. By default it is read from your server root, and `--config <path>` points at one anywhere else. Package locations inside it resolve against the directory holding the config, so a config kept next to its packages travels with them.

**Important:** Publisher does not support environment variable substitution. Put actual credential values directly in the config file.
**Keeping credentials out of the file:** any `${VAR}` inside a string value is replaced with that environment variable's value when the config loads, so passwords and keys can stay out of the file and out of version control:

```json
"postgresConnection": {
"host": "${PG_HOST}",
"password": "${PG_PASSWORD}"
}
```

Substitution applies to every string in the config, including package `location` values. Only uppercase, braced names are matched: `$PG_PASSWORD` (no braces) and `${lowercase}` are left as literal text.

This keeps credentials out of the file, not out of the server. Publisher resolves `${VAR}` at load time and then serves the resolved connection configuration, password included, from its API: `/api/v0/environments/{environment}/connections` returns it, and so do `/api/v0/environments` and `/api/v0/status`, the endpoint most people wire into a health check.

Publisher ships with no authentication and binds all interfaces by default, so anyone who can reach the port can read those credentials, run SQL through any connection you have configured, and (unless you set `frozenConfig: true`) add connections of their own. This is not only a concern for servers that hold credentials: the DuckDB sandbox every package gets automatically will also read files off the server's filesystem, so even a Publisher with no connections configured at all exposes its host. Keep Publisher on a trusted network or behind your own authentication.

Set every variable your config references before starting. If one is unset, the whole config fails to load and Publisher comes up serving nothing, which is easy to miss because `/api/v0/status` still reports `"operationalState": "serving"`. Check `/api/v0/environments` to confirm your environments actually loaded. A variable that is set but empty is not an error: it substitutes an empty string, so a blank `${PG_PASSWORD}` becomes a blank password rather than a failure.

### Basic Structure

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand Down Expand Up @@ -53,7 +68,7 @@ For packages with embedded parquet/CSV files, **no connection configuration is n

```json
{
"projects": [
"environments": [
{
"name": "default",
"packages": [
Expand Down Expand Up @@ -88,16 +103,18 @@ my-analytics/

DuckDB can federate queries to external databases (BigQuery, Snowflake, PostgreSQL) using attached databases. This lets you query cloud data warehouses through DuckDB.

**Note:** the connection name `duckdb` is reserved for the per-package sandbox described above, so an environment-level DuckDB connection needs a different name. Using `duckdb` here does not stop the server: it logs the error, skips that whole environment, and carries on reporting `"operationalState": "serving"` with nothing loaded. These examples use `shared_duckdb`; reference that same name in your Malloy code.

**Attach BigQuery:**

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
{
"name": "duckdb",
"name": "shared_duckdb",
"type": "duckdb",
"duckdbConnection": {
"attachedDatabases": [
Expand All @@ -121,19 +138,19 @@ DuckDB can federate queries to external databases (BigQuery, Snowflake, PostgreS

In your Malloy model:
```malloy
source: events is duckdb.table('my_bq.my_dataset.events')
source: events is shared_duckdb.table('my_bq.my_dataset.events')
```

**Attach Snowflake:**

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
{
"name": "duckdb",
"name": "shared_duckdb",
"type": "duckdb",
"duckdbConnection": {
"attachedDatabases": [
Expand Down Expand Up @@ -162,12 +179,12 @@ source: events is duckdb.table('my_bq.my_dataset.events')

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
{
"name": "duckdb",
"name": "shared_duckdb",
"type": "duckdb",
"duckdbConnection": {
"attachedDatabases": [
Expand Down Expand Up @@ -219,7 +236,7 @@ source: events is duckdb.table('my_bq.my_dataset.events')

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -244,11 +261,11 @@ source: events is duckdb.table('my_bq.my_dataset.events')

**With service account (recommended for production):**

Embed the service account JSON directly in the config:
The service account JSON goes in `serviceAccountKeyJson` as a string. To keep the key out of the file, put it in an environment variable and reference it as `${BIGQUERY_SA_JSON}`:

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -258,7 +275,7 @@ Embed the service account JSON directly in the config:
"bigqueryConnection": {
"defaultProjectId": "my-gcp-project",
"location": "US",
"serviceAccountKeyJson": "{\n \"type\": \"service_account\",\n \"project_id\": \"my-gcp-project\",\n ...rest of service account JSON...\n}"
"serviceAccountKeyJson": "${BIGQUERY_SA_JSON}"
}
}
],
Expand All @@ -268,11 +285,20 @@ Embed the service account JSON directly in the config:
}
```

Then start Publisher with the key in the environment:

```bash
export BIGQUERY_SA_JSON="$(cat service-account.json)"
npx @malloy-publisher/server --server_root .
```

The whole key can also be pasted inline as a JSON string (`"{\n \"type\": \"service_account\", ...}"`) if you would rather not use an environment variable.

**With gcloud auth (development only):**

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -299,7 +325,7 @@ Embed the service account JSON directly in the config:

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -326,7 +352,7 @@ Embed the service account JSON directly in the config:

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand Down Expand Up @@ -355,7 +381,7 @@ Embed the service account JSON directly in the config:

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand Down Expand Up @@ -383,7 +409,7 @@ Embed the service account JSON directly in the config:

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -407,11 +433,11 @@ Embed the service account JSON directly in the config:

---

## Trino and Presto
## Trino

```json
{
"projects": [
"environments": [
{
"name": "default",
"connections": [
Expand All @@ -430,17 +456,15 @@ Embed the service account JSON directly in the config:
}
```

For Presto, use `"type": "presto"` with the same configuration options.

---

## Multi-Environment Configuration

You can configure multiple projects for different environments:
You can configure multiple environments, for example one per deployment stage:

```json
{
"projects": [
"environments": [
{
"name": "staging",
"connections": [
Expand Down
34 changes: 17 additions & 17 deletions src/documentation/user_guides/publishing/explorer.malloynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Deploy Publisher ([see Publishing](publishing.malloynb)) and share the URL with

<img src="explorer-screenshots/publisher-model-list.png" alt="Publisher model list" style="max-width: 900px;">

The URL format is: `http://localhost:4000/project/package/model`
The URL format is: `http://localhost:4000/<environment>/<package>/<model-path>`, where the model path includes the file extension, for example `http://localhost:4000/examples/storefront/storefront.malloy`.

Anyone with access to Publisher can explore your semantic models—no Malloy knowledge required.

Expand Down Expand Up @@ -61,9 +61,9 @@ The panel is organized into three sections:
Attributes you can group by, filter on, or sort with. Dimensions are grouped by their source. For example, in a query centered around `order_items`, you might also see dimensions from joined models like `users` or `products`.

Hovering over a dimension reveals actions:
- **Add as Group By** – Segment results by this dimension
- **Add as Filter** – Apply a filter based on the field
- **Add as Sort** – Sort results by this value
- **Add as group by** – Segment results by this dimension
- **Add as filter** – Apply a filter based on the field
- **Add as order by** – Sort results by this value (only available for fields already in the output)

<img src="explorer-screenshots/source-panel-dimension-hover-groupby.png" alt="Dimension Hover Actions" style="max-width: 250px;">

Expand All @@ -72,9 +72,9 @@ Hovering over a dimension reveals actions:
Predefined metrics you can aggregate, filter on, or sort with. These include calculations such as totals, averages, counts, and ratios.

Hovering over a measure provides actions:
- **Add as Aggregate** – Include the metric in results
- **Add as Filter** – Use the measure to restrict results
- **Add as Sort** – Sort results based on the metric value
- **Add as aggregate** – Include the metric in results
- **Add as filter** – Use the measure to restrict results
- **Add as order by** – Sort results based on the metric value (only available for fields already in the output)

<img src="explorer-screenshots/source-panel-measure-hover-aggregate.png" alt="Measure Hover Actions" style="max-width: 250px;">

Expand All @@ -83,8 +83,8 @@ Hovering over a measure provides actions:
Saved queries defined in the underlying Malloy model. Views often represent curated KPIs, commonly-used explorations, or analytical building blocks.

Hovering over a view provides actions:
- **Add to Query** – Load the view's query
- **Add as Nested Query** – Add the view as a nested subquery
- **Add view** – Load the view's query
- **Add as new nested query** – Add the view as a nested subquery

<img src="explorer-screenshots/source-panel-view-hover-add-to-query.png" alt="View Hover Actions" style="max-width: 260px;">

Expand All @@ -108,13 +108,13 @@ The Query Panel is where queries come together. It provides a structured, visual

This menu lets you add fields by operation type:

- Add Group By
- Add Aggregate
- Add Filter
- Add View
- Add group by
- Add aggregate
- Add filter
- Add view
- Limit
- Order By
- Add Blank Nested Query
- Order by
- Add blank nested query

<img src="explorer-screenshots/query-panel-add-action.png" alt="Add Query Element" style="max-width: 675px;">

Expand Down Expand Up @@ -155,8 +155,8 @@ Hovering over a section shows additional ways to add elements.
Malloy's nesting feature enables rich, multidimensional analysis—and Explorer gives you a no-code way to use it.

To add a nested query:
- Select **Nest Query** from the Query Panel **More Actions** menu
- Or hover over a view in the Source Panel and select **Add as Nested Query**
- Select **Nest query** from the Query Panel **More Actions** menu
- Or hover over a view in the Source Panel and select **Add as new nested query**

<img src="explorer-screenshots/query-panel-more-nest.png" alt="Nest Action" style="max-width: 350px;">

Expand Down
Loading
Loading