Malloy Documentation
search

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:

document
import "flights.malloy"

run: flights -> { limit: 5; group_by: carrier; aggregate: flight_count }
QUERY RESULTS
[
  {
    "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.

document
import { airports, spaceports is airports } from "airports.malloy"

run: airports -> { aggregate: airport_count is count() }
run: spaceports -> { aggregate: spaceport_count is count() }
QUERY RESULTS
[
  {
    "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 export statement 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 the export statement out entirely.