On this page:
9.1.1 Required Fields
author-string?
9.1.2 Optional Fields
9.1.3 Collections
render-spec?
9.1.4 Feeds
feed-filename?
9.1.5 Source/  Output Path Mapping
source-path-pattern?
output-path-pattern?
format-output-path
file-extension?
non-rkt-file-extension?
9.1.6 Site Configuration API
site
collection
feed-config
load-site
resolve-site-spec
file-path->site-path
load-book
9.2.0.5

9.1 Site Configuration Language🔗ℹ

 #lang camp/site package: camp-lib

A Camp site is a single website, organized as a Racket package.

A site has one or more collections, which are named groups of pages with a sort order, a mapping between source and output paths, and optional taxonomies for further organization.

A page is a single source document.

A feed is an RSS or Atom feed which includes all pages from a set of one or more collections. A site may specify zero feeds, one feed, or multiple feeds.

The #lang camp/site language provides a TOML-based configuration format for defining Camp sites. Files written in this language are parsed and validated against the site schema.

#lang camp/site
 
# Required values ------
title = "Site Title"
url = "https://example.com"
founded = 1912-07-04              # Note no quotes
authors = ["Me (me@example.com)"] # List of strings, must be in this format
 
# Optional values ------
sources = ".mypage"         # .md.rkt and .page.rkt are always recognized
static-folder = "res"       # default is "static"
output-folder = "public"    # default is "publish"
deploy-script = "deploy.sh"
default-render = "(camp-demo/render render-page)"
#  string datum: list of module and a function identifier
# function signature: Document, Context -> Xexpr
 
# Collections ----------
 
[[collections]]
name = "blog"
source = "blog/*"
output-paths = "blog/[yyyy]/[MM]/*/"
render-with = "(camp-demo/render render-post)" # same as default-render
order = "descending"
sort-key = "date"
taxonomies = ["tags", "series"]
 
[[collections]]
name = "pages"
source = "pages/*"
output-paths = "*/"
render-with = "(camp-demo/render render-page)"
sort-key = "title"
order = "ascending"
 
[[feeds]]
filename = "feed.atom" # Extension .atom or .rss sets format
collections = ["blog"] # List of collection names
render-with = "(camp-demo/feeds feed-content)" # same as default-render

9.1.1 Required Fields🔗ℹ

Field

Type

Description

title

string?

Site title

url

valid-url-string?

Base URL (must be valid)

founded

date?

Founding date for tag URI generation

authors

(listof author-string?)

Authors in "Name (email)" format

procedure

(author-string? v)  boolean?

  v : any/c
Returns #t if v is a string in "Name (email@example.com)" format, where email is a valid email address per email-address? from splitflap.

Examples:
> (author-string? "Me (me@example.com)")

#t

> (author-string? "Me (me@1.com)")

#f

> (author-string? " (me@example.com)")

#f

9.1.2 Optional Fields🔗ℹ

Field

Type

Default

Description

sources

non-rkt-file-extension?

".md.rkt"

Source file extension

static-folder

path-string?

"static"

Static assets directory

output-folder

path-string?

"publish"

Build output directory

deploy-script

path-string?

#f

Deployment script path

default-render

render-spec?

#f

Default render function

9.1.3 Collections🔗ℹ

Each [[collections]] entry defines a group of source documents:

Field

Type

Default

Description

name

string?

Collection identifier

source

source-path-pattern?

Location of sources

output-paths

output-path-pattern?

Defines output paths/URLs

render-with

render-spec?

Render function specification

taxonomies

(listof string?)

(Optional) metadata keys

sort-key

string?

"date"

Metadata sort key

order

(or/c "ascending" "descending")

"descending"

Sort order

procedure

(render-spec? v)  (or/c #f (listof module-path? symbol?))

  v : any/c
Validates that v is a string containing a two-element list, with the first element being a module-path? and the second being an identifier. Returns the two-element list if validation succeeds, or #f otherwise.

In order to be valid, at site build time the identifier must be that of a function provided by the module, and the function must have the signature (-> document? context? xexpr?). This information is not checked by render-spec?, however.

Examples:
> (render-spec? "(my-module render-func)")

'(my-module render-func)

> (render-spec? "(\"mod.rkt\" func)")

'("mod.rkt" func)

> (render-spec? "(100)")

#f

9.1.4 Feeds🔗ℹ

Each [[feeds]] entry defines an RSS or Atom feed:

Field

Type

Description

filename

feed-filename?

Output filename (.atom or .rss)

collections

(listof string?)

Collection names to include

render-with

render-spec?

Feed content render function

Each feed’s render-with value should identify a function with the same signature as page render functions:

(define (feed-content doc ctxt)
  ;; doc: the Punct document
  ;; ctxt: same context as page render functions (slug, url, collection, etc.)
  ;; Returns x-expression for the feed entry body
  `(article ,@(document-body doc)
            (p (a ((href ,(context-url ctxt))) "Read more..."))))

The ctxt argument is a context whch provides access to the page’s canonical URL, enabling feed content to include links back to the original page on your site.

procedure

(feed-filename? v)  boolean?

  v : any/c
Returns #t if v is a string ending in ".atom" or ".rss".

Examples:
> (feed-filename? "posts.atom")

#t

> (feed-filename? "blog.rss")

#t

> (feed-filename? "comments")

#f

9.1.5 Source/Output Path Mapping🔗ℹ

Camp uses path patterns to map source files to output locations.

A source path pattern specifies where to find source documents within a collection (e.g., "blog/*"). An output path pattern specifies the URL structure for rendered pages, with support for slug substitution and date-based paths (e.g., "blog/[yyyy]/[MM]/*/").

An output path pattern specifies the folder/file structure (and thus the URL) for rendered pages, with support for slug substitution, date-based paths, and meta value interpolation. In output path patterns:

  • Any folder name consisting only of * will be replaced by the source’s slug.

  • Any name inside a pair of brackets [] will first be looked up as a key in the source’s metadata. If a matching meta key is found, the bracket is replaced by that value. Otherwise, the name is interpreted as a CLDR date format code and formatted using the source’s date meta.

  • If the pattern ends in a trailing slash /, the output file will be named "index.html". Otherwise the output is the name of the pattern’s final element with an added ".html" extension.

  • A pattern must contain at least one * or [] element.

procedure

(source-path-pattern? v)  boolean?

  v : any/c
Returns #t if v is a valid source path pattern: a relative path string that does not contain . or .. components, and whose final element is *.

Examples:
> (source-path-pattern? "writing/*")

#t

> (source-path-pattern? "/writing/*")

#f

> (source-path-pattern? "writing/")

#f

> (source-path-pattern? "../writing/*")

#f

procedure

(output-path-pattern? v)  boolean?

  v : any/c
Returns #t if v is a valid output path pattern: a relative path string that does not contain . or .. components, and contains at least one * element or bracketed pattern.

Examples:
> (output-path-pattern? "posts/*/")

#t

> (output-path-pattern? "posts/[YYYY]/*/")

#t

> (output-path-pattern? "../posts/*/")

#f

> (output-path-pattern? "posts/")

#f

procedure

(format-output-path pattern slug date metas)  path?

  pattern : output-path-pattern?
  slug : string?
  date : (or/c date-provider? #f)
  metas : (or/c hash? #f)
Applies an output path pattern to produce an output file path. The slug replaces * in the pattern. Bracketed patterns are resolved by first checking metas for a matching key; if no match is found, the pattern is interpreted as a CLDR date code and formatted using date.

Examples:
> (format-output-path "posts/*/" "hello-world" #f #f)

#<path:posts/hello-world/index.html>

> (format-output-path "blog/[yyyy]/[MM]/*/" "my-post" (date 2025 1 15) #f)

#<path:blog/2025/01/my-post/index.html>

> (format-output-path "newsletter/[issue]/*/" "my-post" #f (hasheq 'issue 42))

#<path:newsletter/42/my-post/index.html>

procedure

(file-extension? v)  boolean?

  v : any/c
Returns #t if v is a valid file extension: a string or byte string starting with . and containing no directory separators.

procedure

(non-rkt-file-extension? v)  boolean?

  v : any/c
Returns #t if v is a valid file extension other than ".rkt".

Examples:
> (non-rkt-file-extension? ".myformat.rkt")

#t

> (non-rkt-file-extension? ".rkt")

#f

9.1.6 Site Configuration API🔗ℹ

The following data types from camp underlie the site configuration language. They are represented as hash-views: hash tables with struct-like accessor functions. For more information on hash-views, see hash-view: Struct-like Views of Hashes.

hash-view

(hash-view site (title
    url
    founded
    authors
    [sources #:default ....]
    [static-folder #:default ....]
    [output-folder #:default ....]
    collections
    [racket-collection #:default ....]
    [deploy-script #:default ....]
    [default-render #:default ....]
    [feeds #:default ....]))
  title : string?
  url : valid-url-string?
  founded : date-provider?
  authors : (listof string?)
  sources : string? = ".md.rkt"
  static-folder : string? = "static"
  output-folder : string? = "publish"
  collections : (listof collection?)
  racket-collection : (or/c string? #f)
  deploy-script : (or/c string? #f)
  default-render : (or/c list? #f)
  feeds : (listof feed-config?) = '()
A hash-view representing a site configuration. A site is most commonly defined using #lang camp/site.

Required fields are title, url, founded, authors, and collections.

The racket-collection field is set automatically by load-site from the package’s "info.rkt". It contains the Racket collection name (e.g., "myblog") and is #f if the site is not installed as a package.

hash-view

(hash-view collection (name
    source
    output-paths
    render-with
    [order #:default ....]
    [sort-key #:default ....]
    taxonomies))
  name : string?
  source : source-path-pattern?
  output-paths : output-path-pattern?
  render-with : (or/c list? #f)
  order : string? = "descending"
  sort-key : string? = "date"
  taxonomies : (listof string?)
A hash-view representing a collection configuration. Collections are most commonly defined as part of a #lang camp/site configuration module.

Required fields are name, source, and output-paths.

hash-view

(hash-view feed-config (filename
    collections
    render-with))
  filename : string?
  collections : (listof string?)
  render-with : list?
A hash-view representing a feed configuration. Feed configurations are most commonly defined as part of a #lang camp/site configuration module. All fields are required.

procedure

(load-site mod-path)  site?

  mod-path : 
(or/c path-string? module-path?
       (and/c hash? (λ (h) (hash-has-key? h 'path))))
Loads a site configuration from a #lang camp/site module. The mod-path can be:
  • A filesystem path to a "site.rkt" file

  • A module path like 'my-site/site

  • A hash containing a 'path key (such as a book configuration returned by load-book)—the site is discovered from the package’s "info.rkt"

Returns the parsed site configuration as a hash-view with an additional 'root key containing the absolute path to the site’s directory.

Calling load-site again in the same process reflects any changes saved to the configuration module in the meantime; the GUI app and raco camp serve rely on this to reload the site when its configuration changes.

When called in a live-reloading context (the GUI app, or raco camp serve with watching enabled), load-site also deletes any compiled bytecode ("compiled" folders) under the site’s directory, except within the output and static folders. Bytecode produced by raco setup prevents modules from being reloaded after edits, so a live session must load site modules from source; one-shot commands like raco camp build leave bytecode alone and use it as usual.

procedure

(resolve-site-spec spec)  (or/c path? #f)

  spec : (or/c path? string? symbol?)
Resolves a site specification to a path. The spec can be:
  • A path?: Returns the path if it exists as a file, #f otherwise.

  • A string?: If it exists as a file, returns it as a path. Otherwise, treats it as a collection name and searches installed packages.

  • A symbol?: Treats the symbol as a collection name and searches installed packages.

When searching by collection name, finds packages with a 'camp-site field in their "info.rkt" whose 'collection name matches.

(resolve-site-spec "site.rkt")       ; path if file exists
(resolve-site-spec "myblog")         ; finds myblog package
(resolve-site-spec 'myblog)          ; same, with symbol

procedure

(file-path->site-path file-path)  path?

  file-path : path-string?
Discovers the site configuration path for a file within a Camp package. Uses path->pkg+subpath to find the package root, then reads the 'camp-site field from the package’s "info.rkt".

Raises an error if the file is not in a package, no "info.rkt" exists, or the 'camp-site field is not defined.

procedure

(load-book file-path)  book?

  file-path : path-string?
Loads a book configuration from a #lang camp/book module. Returns the parsed book configuration as a hash-view with an additional 'path key containing the absolute path to the book file.

To load the associated site for a book:

(define mybook (load-book "path/to/my.book.rkt"))
(define mysite (load-site book))  ; discovers site from package info.rkt