In order to reuse or extend a source from another file, you can include all the
exported sources from another file using import "path/to/some/file.malloy".
For example, if you wanted to create a file flights_by_carrier.malloy with a query from the flights source, you could write:
import "flights.malloy" run: flights -> { limit: 5; group_by: carrier; aggregate: flight_count }
[ { "carrier": "WN", "flight_count": 88751 }, { "carrier": "US", "flight_count": 37683 }, { "carrier": "AA", "flight_count": 34577 }, { "carrier": "NW", "flight_count": 33580 }, { "carrier": "UA", "flight_count": 32757 } ]
SELECT base."carrier" as "carrier", COUNT(1) as "flight_count" FROM '../data/flights.parquet' as base GROUP BY 1 ORDER BY 2 desc NULLS LAST LIMIT 5
Import Locations
Imported files may be specified with relative or absolute URLs.
| Import Statement | Meaning from "file:///f1/a.malloy" |
|---|---|
import "b.malloy" |
"file:///f1/b.malloy" |
import "./c.malloy" |
"file:///f1/c.malloy" |
import "/f1/d.malloy" |
"file:///f1/d.malloy" |
import "file:///f1/e.malloy" |
"file:///f1/e.malloy" |
import "../f2/f.malloy" |
"file:///f2/f.malloy" |
import "https://example.com/g.malloy" |
"https://example.com/g.malloy" |
Selective Imports
The default is to import all objects from the referenced file. You can also use {} from to select (and optionally rename) specific objects to be imported.
import { airports, spaceports is airports } from "airports.malloy" run: airports -> { aggregate: airport_count is count() } run: spaceports -> { aggregate: spaceport_count is count() }
[ { "spaceport_count": 19793 } ]
SELECT COUNT(1) as "spaceport_count" FROM '../data/airports.parquet' as base
Exports
By default, every source:, query:, given:, and type: declared in a file is exported — that is, visible to anyone who imports the file. If you'd rather keep some definitions local (for example, helper sources used only as scaffolding for the things you actually publish), add an export { ... } statement listing only the names you want to expose:
source: raw_flights is duckdb.table('flights.parquet') source: flights is raw_flights extend { measure: flight_count is count() } export { flights }
After this, flights is exported but raw_flights is not. raw_flights is still usable inside the file — only its visibility from other files is affected.
The syntax intentionally mirrors selective import:
import { flights } from "flights.malloy" export { flights }
export is opt-in. A file with no export statement behaves exactly as before: everything declared is exported.
Multiple export statements add together:
source: a is duckdb.table('a.parquet') export { a } source: b is duckdb.table('b.parquet') export { b } // exports are now { a, b }
You can re-export an imported name. This is the natural way to build a curated library on top of another:
import { customers is raw_customers } from "raw.malloy" source: orders is duckdb.table('orders.parquet') export { customers, orders }
Rules
An
exportstatement must appear after the definition of each name it lists. Forward references are an error.Only sources, queries, givens, and user types can be exported. Connections cannot.
There is no rename on export — rename at the definition site if you need a different public name.
There is no
export *. The way to "export everything" is to leave theexportstatement out entirely.