On this page:
8.1.1 Required Fields
author-string?
8.1.2 Optional Fields
8.1.3 Collections
render-spec?
8.1.4 Feeds
feed-filename?
8.1.5 Source/  Output Path Mapping
source-path-pattern?
output-path-pattern?
format-output-path
file-extension?
non-rkt-file-extension?
8.1.6 Site Configuration API
site
collection
feed-config
load-site
resolve-site-spec
file-path->site-path
load-book
9.1

8.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

8.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

8.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

8.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

8.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

8.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

8.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.

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