Written by Bjørn Erling Fløtten, Trondheim, Norway. Updated 27 Apr 2026.

License: CC BY 4.0.

Typst: Scope, include, imports and templates, functions and variables

This article demonstrates scope in typst through 10 practical examples (zip file). It applies to typst version 0.14.2 (b33de9de). Typst is a markup-based typesetting system designed as an alternative to LaTeX

The TL;DR is that you can not make global imports (issue 595) and neither can you literally input files (issue 4194). Both of these issues are "Closed as not planned" because they go against the core design of typst.

The solution is simply to repeat imports wherever needed. This is demonstrated in the final example (Ex 10)

Below we explain our process at work trying to understand this (before we finally ended up with the aforementioned conclusion).

Background: We wanted to apply a consistent formatting throughout the document, and also to make variables and functions available globally. The issue was complicated by the fact that our document has multiple simultaneous versions, three levels of inclusions (top level, chapter, sub chapter) and a mix of autogenerated and manually written text.

We got distracted by attempting to accomplish two things at the same time: Use a template and also import variables and functions. The template syntax can also be a bit difficult to grasp. The 10 examples below are an attempt at clarifying all this. You can download the zip file for experimenting locally.

Go to TL;DR for the final working example which also works for sub chapters. The solution was simply to repeat imports wherever they are needed and to not mix up template import with variable and function import.

Ex 1: Define directly in same document

Defining formatting, variables and functions together with the text in the same document works as expected.

main.typ:

#show heading.where(level: 1): set text(size: 30pt)

#set page(
  header: [
    My header
  ],
)

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    [#text]   
  )
}

= My heading with size 30pt

This page has the header "My header" at top

#MY_VARIABLE

#warning([My warning])

Result: main.pdf

Ex 2: #include, not compiling

Trying to split out formatting to a separate file causes problems. This is somewhat expected. What we define in an include file should not be present in the scope of the main file.

include.typ:

#show heading.where(level: 1): set text(size: 30pt)

#set page(
  header: [
    My header
  ],
)

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    [#text]   
  )
}

main.typ:

#include "include.typ"

= My heading

// Non-resolving reference
#MY_VARIABLE

// Non-resolving reference
#warning([My warning])

Result: Not available.

Ex 3: #include, compiling, not working

The sample below compiles but note that "nothing" gets included from the include file, not even page setup or headers

include.typ:

#show heading.where(level: 1): set text(size: 30pt)

#set page(
  header: [
    My header
  ],
)

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    [#text]   
  )
}

main.typ:

#include "include.typ"

= My heading with wrong size

This page has no header on it.

// Non-resolving reference
// #MY_VARIABLE

// Non-resolving reference
// #warning([My warning])

Result: main.pdf.

Ex 4: #include, "opposite" manner, not compiling

Including files in the "opposite" manner does not compile either. That is, having formatting in the main file and include the text does not compile. This was (for us at least) the surprising part because now the text part is hierarchically "below" the main file. One could naïvely expect that "everything" in the main file carries through to the included files but it does not.

main.typ:

#show heading.where(level: 1): set text(size: 30pt)

#set page(
  header: [
    My header
  ],
)

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    [#text]   
  )
}

#include "include.typ"

include.typ:

= My heading

// Non-resolving reference
#MY_VARIABLE

// Non-resolving reference
#warning([My warning])

Result: Not available.

Ex 5: #include, "opposite" manner, compiling, partly working

Including files in the "opposite" manner works for the "show heading" and "set page" though. But "MY_VARIABLE" and "warning" do not resolve.

main.typ:

#show heading.where(level: 1): set text(size: 30pt)

#set page(
  header: [
    My header
  ],
)

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    [#text]   
  )
}

#include "include.typ"

include.typ:

= My heading with size 30pt

This page has the header "My header" at top

// Non-resolving reference
// #MY_VARIABLE

// Non-resolving reference
// #warning([My warning])  

Result: main.pdf.

Ex 6: #import as Template, not compiling

Using #import as template brings us closer to a solution. See Ex 7 for a partly working example.

include.typ:

#let MyTemplate(body) = {
  show heading.where(level: 1): set text(size: 30pt)

  set page(
    header: [
      My header
    ],
  )

  let MY_VARIABLE = "My variable"

  let warning(text) = {
    rect(
      fill:(rgb("#fdba74")),
      radius: 4pt,
      [#text]   
    )
  }

  body
}

main.typ:

#import "include.typ":MyTemplate
#show: MyTemplate
// The "body" parameter to the Template function is implicitly
// understood to be everything from here and below

= My heading with size 30pt

This page has the header "My header" at top

// Non-resolving reference
#MY_VARIABLE

// Non-resolving reference
#warning([My warning])  

Result: Not available.

Ex 7: #import as Template, compiling, partly working

If we do not reference "MY_VARIABLE" and "warning" then the code compiles. But then we are back to what we accomplished in Ex 6.

include.typ:

#let MyTemplate(body) = {
  show heading.where(level: 1): set text(size: 30pt)

  set page(
    header: [
      My header
    ],
  )

  let MY_VARIABLE = "My variable"

  let warning(text) = {
    rect(
      fill:(rgb("#fdba74")),
      radius: 4pt,
      [#text]   
    )
  }

  body
}

main.typ:

#import "include.typ":MyTemplate
#show: MyTemplate
// The "body" parameter to the Template function is implicitly
// understood to be everything from here and below

= My heading with size 30pt

This page has the header "My header" at top

// Non-resolving reference
// #MY_VARIABLE

// Non-resolving reference
// #warning([My warning])  

Result: main.pdf.

Ex 8: #import as Template, working example

We can define "MY_VARIABLE" and "warning" separately in the include file and import them separately.

include.typ:

#let MyTemplate(body) = {
  show heading.where(level: 1): set text(size: 30pt)

  set page(
    header: [
      My header
    ],
  )

  body
}

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    text
  )
}

main.typ:

#import "include.typ":MyTemplate, MY_VARIABLE, warning
#show: MyTemplate
// The "body" parameter to the Template function is implicitly
// understood to be everything from here and below

= My heading with size 30pt

This page has the header "My header" at top

#MY_VARIABLE

#warning([My warning])  

Result: main.pdf.

Ex 9: #import as Template, using chapter files, not compiling

The last example does not work if we introduce a typst file for each chapter though. This is similar to what was demonstrated in Ex 4 so it should not come as a surprise.

include.typ:

#let MyTemplate(body) = {
  show heading.where(level: 1): set text(size: 30pt)

  set page(
    header: [
      My header
    ],
  )

  body
}

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    text
  )
}

main.typ:

#import "include.typ":MyTemplate, MY_VARIABLE, warning
#show: MyTemplate
// The "body" parameter to the Template function is implicitly
// understood to be everything from here and below

#include "chapter1.typ"

chapter1.typ:

= My heading with size 30pt

This page has the header "My header" at top

// Non-resolving reference
#MY_VARIABLE

// Non-resolving reference
#warning([My warning])  

Result: Not available.

Ex 10: #import as Template, using chapter files, repeating other import

The final solution is to repeat the import whenever needed and to not mix up template import with variable and function import.

include.typ:

#let MyTemplate(body) = {
  show heading.where(level: 1): set text(size: 30pt)

  set page(
    header: [
      My header
    ],
  )

  body
}

#let MY_VARIABLE = "My variable"

#let warning(text) = {
  rect(
    fill:(rgb("#fdba74")),
    radius: 4pt,
    text
  )
}

main.typ:

#import "include.typ":MyTemplate
#show: MyTemplate
// The "body" parameter to the Template function is implicitly
// understood to be everything from here and below

#include "chapter1.typ"

chapter1.typ:

#import "include.typ":MY_VARIABLE, warning

= My heading with size 30pt

This page has the header "My header" at top

#MY_VARIABLE

#warning([My warning])  

Result: main.pdf.

Conclusion: Repeat imports wherever needed.

So the conclusion is simply to repeat an import wherever it is needed.

Final hint: If you would like to organize the chapters into subfolders you might have to use to "--root" argument to "typst compile" in order for typst to accept including files from "above" the chapter folder.

Contact: