Standard Library

Quill comes with 60+ built-in functions that are available everywhere — no imports needed. This page documents every function with plain English explanations and practical examples.

New to programming? Think of the standard library as a toolbox. Just like a carpenter has a hammer, saw, and measuring tape, Quill gives you ready-made tools for working with text, lists, numbers, files, and more. You don't need to build these tools yourself — they're already here for you.

Working with Lists

Lists are one of the most useful things in programming. A list is just a collection of items — like a shopping list, a list of names, or a list of scores. These functions help you create, search, filter, transform, and analyze lists.

length(x) — Count items

Returns the number of items in a list (or characters in text). This is one of the most common functions you'll use.

-- How many items in my list?
fruits are ["apple", "banana", "cherry"]
say length(fruits)   -- 3

-- Also works on text
say length("hello")   -- 5

-- Practical: check if a list is empty
if length(results) is 0:
  say "No results found"

push(list, item) — Add an item

Adds an item to the end of a list. Like adding something to the bottom of your to-do list.

tasks are ["buy milk", "walk dog"]
push(tasks, "call mom")
say tasks   -- ["buy milk", "walk dog", "call mom"]

pop(list) — Remove the last item

Removes and returns the last item from a list.

stack are [1, 2, 3]
last is pop(stack)
say last    -- 3
say stack   -- [1, 2]

sort(list) — Sort items

Returns a new list with items sorted in order (smallest to largest for numbers, A-Z for text). The original list is not changed.

scores are [85, 92, 71, 100, 63]
say sort(scores)   -- [63, 71, 85, 92, 100]

names are ["Charlie", "Alice", "Bob"]
say sort(names)   -- ["Alice", "Bob", "Charlie"]

reverse(list) — Reverse order

Returns a new list with items in the opposite order.

countdown are [1, 2, 3, 4, 5]
say reverse(countdown)   -- [5, 4, 3, 2, 1]

unique(list) — Remove duplicates

Returns a new list with duplicate items removed. Like removing repeat entries from a guest list.

tags are ["js", "python", "js", "go", "python"]
say unique(tags)   -- ["js", "python", "go"]

includes(list, item) — Check if item exists

Returns yes if the list contains the item, no otherwise. Like checking if a name is on a guest list.

colors are ["red", "green", "blue"]
say includes(colors, "green")    -- true
say includes(colors, "purple")   -- false

indexOf(list, item) — Find position

Returns the position (index) of an item in a list. Returns -1 if not found. Remember: positions start at 0, not 1.

letters are ["a", "b", "c", "d"]
say indexOf(letters, "c")   -- 2 (third item, but index starts at 0)
say indexOf(letters, "z")   -- -1 (not found)

slice(list, start, end) — Get a portion

Returns a portion of a list from start to end (not including end). Like cutting a section out of a list.

numbers are [10, 20, 30, 40, 50]
say slice(numbers, 1, 4)   -- [20, 30, 40]
say slice(numbers, 2)       -- [30, 40, 50] (from index 2 to the end)

concat(a, b) — Combine two lists

Joins two lists together into one new list.

first are [1, 2]
second are [3, 4]
say concat(first, second)   -- [1, 2, 3, 4]

flat(list) — Flatten nested lists

Takes a list of lists and flattens it into a single list.

nested are [[1, 2], [3, 4], [5]]
say flat(nested)   -- [1, 2, 3, 4, 5]

range(start, end) — Generate number sequences

Creates a list of numbers from start up to (but not including) end. Very useful for generating sequences.

say range(1, 6)    -- [1, 2, 3, 4, 5]
say range(0, 10)   -- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

zip(a, b) — Pair up items

Takes two lists and pairs them up into a list of pairs. Like matching students with their grades.

names are ["Alice", "Bob", "Charlie"]
scores are [95, 82, 91]
say zip(names, scores)
-- [["Alice", 95], ["Bob", 82], ["Charlie", 91]]

sum(list) — Add up numbers

Returns the total of all numbers in a list.

prices are [9.99, 14.50, 3.25]
say sum(prices)   -- 27.74

smallest(list) / largest(list) — Find extremes

Find the smallest or largest value in a list of numbers.

temps are [72, 68, 75, 61, 80]
say smallest(temps)   -- 61
say largest(temps)    -- 80

filter(list, function) — Keep matching items

Creates a new list containing only the items that pass a test. Think of it like a sieve — only items that match your criteria get through.

-- Keep only even numbers
numbers are [1, 2, 3, 4, 5, 6, 7, 8]
evens is filter(numbers, with n: n % 2 is 0)
say evens   -- [2, 4, 6, 8]

-- Keep only names that start with "A"
names are ["Alice", "Bob", "Anna", "Charlie"]
aNames is filter(names, with n: startsWith(n, "A"))
say aNames   -- ["Alice", "Anna"]

map_list(list, function) — Transform every item

Creates a new list by applying a function to every item. Like running each item through a machine that changes it.

-- Double every number
numbers are [1, 2, 3, 4, 5]
doubled is map_list(numbers, with n: n * 2)
say doubled   -- [2, 4, 6, 8, 10]

-- Make all names uppercase
names are ["alice", "bob"]
say map_list(names, with n: upper(n))   -- ["ALICE", "BOB"]

find(list, function) — Find first match

Returns the first item that passes a test. Returns nothing if no match is found.

users are [
  {name: "Alice", age: 30},
  {name: "Bob", age: 17},
  {name: "Charlie", age: 25}
]
adult is find(users, with u: u.age is greater than 18)
say adult.name   -- "Alice"

every(list, function) — Do ALL items match?

Returns yes if every single item passes the test.

ages are [25, 30, 18, 42]
allAdults is every(ages, with a: a is greater than 17)
say allAdults   -- true

some(list, function) — Does ANY item match?

Returns yes if at least one item passes the test.

scores are [45, 62, 38, 91]
anyPassing is some(scores, with s: s is greater than 60)
say anyPassing   -- true

reduce(list, function, initial) — Combine into one value

Takes a list and combines all items into a single value by applying a function repeatedly. This is like folding a list down into one result.

-- Sum all numbers (the long way)
numbers are [1, 2, 3, 4, 5]
total is reduce(numbers, with a, b: a + b)
say total   -- 15

-- Find the longest word
words are ["cat", "elephant", "dog"]
longest is reduce(words, with a, b: if length(a) is greater than length(b) then a otherwise b)

countWhere(list, function) — Count matches

Counts how many items pass a test.

ages are [15, 22, 17, 30, 12]
adults is countWhere(ages, with a: a is greater than 17)
say adults   -- 2

groupBy(list, function) — Group items

Splits a list into groups based on a function. Returns an object where keys are group names and values are lists.

people are [
  {name: "Alice", dept: "engineering"},
  {name: "Bob", dept: "design"},
  {name: "Charlie", dept: "engineering"}
]
teams is groupBy(people, with p: p.dept)
-- { engineering: [{...}, {...}], design: [{...}] }

Working with Text

Text (also called "strings" in other languages) is everywhere in programming — names, messages, file contents, web pages. These functions help you search, transform, and manipulate text.

trim(text) — Remove extra spaces

Removes spaces (and tabs, newlines) from the beginning and end of text. Very useful when processing user input.

input is "  hello world  "
say trim(input)   -- "hello world"

upper(text) / lower(text) — Change case

Converts text to ALL UPPERCASE or all lowercase.

say upper("hello")   -- "HELLO"
say lower("HELLO")   -- "hello"

-- Useful for case-insensitive comparisons
if lower(answer) is "yes":
  say "Confirmed!"

capitalize(text) — Capitalize first letter

Makes the first letter uppercase. Good for formatting names and titles.

say capitalize("hello")   -- "Hello"
say capitalize("alice")   -- "Alice"

replace_text(text, old, new) — Find and replace

Replaces all occurrences of old with new in the text.

msg is "Hello, World! Hello, Everyone!"
say replace_text(msg, "Hello", "Hi")
-- "Hi, World! Hi, Everyone!"

startsWith(text, prefix) / endsWith(text, suffix)

Check if text begins or ends with a specific string. Returns yes or no.

filename is "photo.jpg"
say endsWith(filename, ".jpg")   -- true
say startsWith(filename, "doc")  -- false

split(text, separator) — Break text apart

Splits text into a list using the separator. Like cutting a sentence into individual words.

-- Split by comma
csv is "apple,banana,cherry"
fruits is split(csv, ",")
say fruits   -- ["apple", "banana", "cherry"]

-- Split by space to get words
sentence is "the quick brown fox"
say split(sentence, " ")   -- ["the", "quick", "brown", "fox"]

join(list, separator) — Combine into text

The opposite of split — joins a list of items into a single text string. Defaults to ", " if no separator given.

colors are ["red", "green", "blue"]
say join(colors, " and ")   -- "red and green and blue"
say join(colors)             -- "red, green, blue"

words(text) — Split into words

Splits text into a list of words (by whitespace). Handles multiple spaces gracefully.

say words("hello  beautiful  world")
-- ["hello", "beautiful", "world"]

lines(text) — Split into lines

Splits text into a list of lines.

poem is "roses are red\nviolets are blue"
say lines(poem)   -- ["roses are red", "violets are blue"]

padStart(text, length, char) / padEnd(text, length, char)

Pads text to a certain length by adding characters to the start or end. Great for formatting numbers and aligning output.

-- Pad a number with leading zeros
say padStart("42", 6, "0")   -- "000042"

-- Pad the end with dots
say padEnd("Loading", 10, ".")   -- "Loading..."

repeat(text, count) — Repeat text

Repeats text a given number of times.

say repeat("ha", 3)     -- "hahaha"
say repeat("=-", 20)   -- a nice separator line

truncate(text, length) — Shorten text

Cuts text to a maximum length and adds ... if it was shortened. Perfect for previews.

title is "This is a very long article title that needs shortening"
say truncate(title, 25)   -- "This is a very long artic..."

Math & Numbers

Functions for rounding, random numbers, and converting between types.

round(n) / floor(n) / ceil(n) — Rounding

round rounds to the nearest whole number. floor always rounds down. ceil always rounds up.

say round(3.7)   -- 4
say round(3.2)   -- 3
say floor(3.9)   -- 3 (always rounds down)
say ceil(3.1)    -- 4 (always rounds up)

abs(n) — Absolute value

Returns the positive version of a number. Removes the negative sign if present.

say abs(-5)    -- 5
say abs(5)     -- 5

random() — Random decimal

Returns a random number between 0 and 1.

say random()   -- 0.7234... (different each time)

randomInt(min, max) — Random whole number

Returns a random whole number between min and max (inclusive). Like rolling dice.

-- Roll a 6-sided die
roll is randomInt(1, 6)
say "You rolled: " + toText(roll)

-- Pick a random card number
card is randomInt(1, 13)

toNumber(x) / toText(x) — Convert types

Convert between numbers and text. You'll use toText often when combining numbers with text in output.

say toNumber("42")       -- 42 (now a number)
say toText(42)           -- "42" (now text)
say "Score: " + toText(100)   -- "Score: 100"

typeOf(x) — Check what type something is

Returns the type of a value as text: "text", "number", "boolean", "list", "object", "nothing", or "function".

say typeOf("hello")   -- "string"
say typeOf(42)        -- "number"
say typeOf([1,2])    -- "list"
say typeOf(nothing)   -- "nothing"

Objects & Data

Objects are like labeled containers — they store values with names (keys). Think of an object as a form with labeled fields: name, age, email. These functions help you inspect, combine, and transform objects.

keys(obj) / values(obj) — Get keys or values

keys returns a list of all the field names. values returns a list of all the values.

user is {name: "Alice", age: 30, city: "NYC"}
say keys(user)     -- ["name", "age", "city"]
say values(user)   -- ["Alice", 30, "NYC"]

entries(obj) — Get key-value pairs

Returns a list of [key, value] pairs. Useful for looping through an object.

config is {theme: "dark", lang: "en"}
for each pair in entries(config):
  say pair[0] + " = " + pair[1]
-- "theme = dark"
-- "lang = en"

fromEntries(pairs) — Build object from pairs

The opposite of entries — creates an object from a list of [key, value] pairs.

pairs are [["name", "Bob"], ["age", 25]]
say fromEntries(pairs)   -- {name: "Bob", age: 25}

merge(obj1, obj2, ...) — Combine objects

Merges multiple objects into one. If the same key appears in multiple objects, the last one wins.

defaults is {theme: "light", lang: "en", fontSize: 14}
userPrefs is {theme: "dark", fontSize: 18}
settings is merge(defaults, userPrefs)
say settings
-- {theme: "dark", lang: "en", fontSize: 18}

pick(obj, keys...) — Select specific fields

Creates a new object with only the fields you want. Like picking columns from a spreadsheet.

user is {name: "Alice", age: 30, email: "alice@example.com", password: "secret"}
safe is pick(user, "name", "email")
say safe   -- {name: "Alice", email: "alice@example.com"}

omit(obj, keys...) — Remove specific fields

The opposite of pick — creates a new object without the specified fields.

safeUser is omit(user, "password")
-- {name: "Alice", age: 30, email: "alice@example.com"}

hasKey(obj, key) — Check if a field exists

say hasKey(user, "name")     -- true
say hasKey(user, "phone")    -- false

deepCopy(x) — Clone a value

Creates a complete independent copy of an object or list. Changes to the copy won't affect the original.

original is {scores: [90, 85, 92]}
copy is deepCopy(original)
push(copy.scores, 100)
say length(original.scores)   -- 3 (unchanged!)
say length(copy.scores)       -- 4

parseJSON(text) / toJSON(value) — JSON conversion

Convert between text (JSON format) and Quill values. JSON is a standard format for storing and exchanging data.

-- Text to object
data is parseJSON("{\"name\": \"Alice\", \"age\": 30}")
say data.name   -- "Alice"

-- Object to formatted text
say toJSON({name: "Bob", age: 25})

Type Checking

Sometimes you need to check what kind of value you're working with before doing something with it. These functions return yes or no.

isText(x) / isNumber(x) / isList(x) / isObject(x)

say isText("hello")     -- true
say isNumber(42)        -- true
say isList([1,2,3])    -- true
say isObject({a: 1})    -- true
say isNumber("42")      -- false (it's text, not a number!)

isNothing(x) / isFunction(x)

say isNothing(nothing)   -- true
say isNothing(0)         -- false (0 is a number, not nothing)
say isNothing("")        -- false (empty text is still text)
Practical use: Type checking is great for writing functions that accept different kinds of input:
to display value:
  if isText(value):
    say value
  otherwise if isList(value):
    say join(value, ", ")
  otherwise:
    say toText(value)

Files & Folders

Read, write, and manage files on your computer. These functions only work when running Quill with the CLI (quill run), not in the browser.

read(path) / write(path, content) — Basic file I/O

Read the entire contents of a file, or write content to a file (creates it if it doesn't exist, overwrites if it does).

-- Read a file
content is read("notes.txt")
say content

-- Write to a file
write("output.txt", "Hello from Quill!")

append_file(path, content) — Add to a file

Adds content to the end of a file without erasing what's already there. Like adding a new entry to a log.

append_file("log.txt", "User logged in at " + now())

readJSON(path) / writeJSON(path, data) — JSON files

Read and write JSON files directly. Quill handles the parsing and formatting for you.

-- Read a config file
config is readJSON("config.json")
say config.name

-- Save data to a file
writeJSON("users.json", [{name: "Alice"}, {name: "Bob"}])

readLines(path) / writeLines(path, list)

Read a file as a list of lines, or write a list of lines to a file.

todos is readLines("todo.txt")
for each todo in todos:
  say "- " + todo

fileExists(path) / exists(path) — Check if file exists

if fileExists("config.json"):
  config is readJSON("config.json")
otherwise:
  say "No config found, using defaults"

listFiles(dir) / listFilesDeep(dir) — List files

listFiles lists files in a directory. listFilesDeep includes all subdirectories too.

files is listFiles(".")
say "Files in current folder: " + join(files, ", ")

fileInfo(path) — Get file details

Returns an object with file size, modification date, and type.

info is fileInfo("photo.jpg")
say "Size: " + toText(info.size) + " bytes"
say "Modified: " + info.modified

copyFile(src, dest) / moveFile(src, dest) / deleteFile(path)

copyFile("report.pdf", "backup/report.pdf")
moveFile("old.txt", "archive/old.txt")
deleteFile("temp.txt")

makeDir(path) — Create folders

Creates a directory (and any parent directories that don't exist yet).

makeDir("output/reports/2026")

Path helpers: joinPath, fileName, fileExtension, parentDir

say joinPath("docs", "guide.txt")       -- "docs/guide.txt"
say fileName("/home/user/photo.jpg")    -- "photo.jpg"
say fileExtension("photo.jpg")          -- ".jpg"
say parentDir("/home/user/photo.jpg")   -- "/home/user"
say currentDir()                          -- your current working directory
say homePath()                            -- your home folder path

Date & Time

Functions for working with dates, times, and timestamps.

now() / today() — Current date/time

say now()     -- "2026-04-04T14:30:00.000Z" (full date and time)
say today()   -- "2026-04-04" (just the date)

timestamp() — Unix timestamp

Returns the current time as milliseconds since January 1, 1970. Useful for measuring how long something takes.

start is timestamp()
-- ... do some work ...
elapsed is timestamp() - start
say "Took " + toText(elapsed) + " ms"

formatDate(date, format) — Format a date

Formats a date string using a pattern. Available placeholders: YYYY (year), MM (month), DD (day), HH (hour), mm (minute), ss (second).

say formatDate(now(), "YYYY-MM-DD")       -- "2026-04-04"
say formatDate(now(), "MM/DD/YYYY")       -- "04/04/2026"
say formatDate(now(), "HH:mm:ss")         -- "14:30:00"

addDays(date, days) / diffDays(date1, date2)

-- What date is 7 days from now?
nextWeek is addDays(today(), 7)
say nextWeek

-- How many days between two dates?
say diffDays("2026-01-01", "2026-04-04")   -- 93

Web & HTTP

Fetch data from the internet and build web servers.

fetchJSON(url) — Get data from an API

Fetches data from a URL and automatically parses it as JSON. This is how you get data from web APIs.

data is await fetchJSON("https://api.example.com/users")
say data

postJSON(url, body) — Send data to an API

result is await postJSON("https://api.example.com/users", {
  name: "Alice",
  email: "alice@example.com"
})

createServer() — Build a web server

Creates an HTTP server with routing. This is how you build web applications and APIs with Quill.

server is createServer()

server.get("/", "Welcome to my site!")

server.get("/api/hello", {message: "Hello from Quill!"})

server.post("/api/data", with req, res:
  say "Got data!"
  give back {status: "ok"}
)

server.listen(3000)
say "Server running on port 3000"

serveStatic(dir) — Serve files

Serves static files (HTML, CSS, images) from a directory.

serveStatic("./public")

Crypto & Encoding

Functions for hashing, generating unique IDs, and encoding/decoding data.

hash(text, algorithm) — Hash a string

Creates a hash (fingerprint) of text. Useful for checksums and verification. Default algorithm is SHA-256.

say hash("hello")              -- "2cf24dba..." (SHA-256)
say hash("hello", "md5")    -- "5d41402a..." (MD5)

uuid() — Generate unique ID

Generates a random unique identifier. Perfect for giving each item a unique ID.

id is uuid()
say id   -- "550e8400-e29b-41d4-a716-446655440000"

encodeBase64(text) / decodeBase64(text)

Encode text to Base64 format and back. Base64 is a way to represent binary data as text.

encoded is encodeBase64("Hello, World!")
say encoded                      -- "SGVsbG8sIFdvcmxkIQ=="
say decodeBase64(encoded)       -- "Hello, World!"

encodeURL(text) / decodeURL(text)

Encode and decode text for safe use in URLs.

say encodeURL("hello world & more")   -- "hello%20world%20%26%20more"
say decodeURL("hello%20world")        -- "hello world"

Patterns & RegExp

Search and replace using patterns (regular expressions). Patterns are like wildcards on steroids — they let you match complex text patterns.

matches(text, pattern) — Find all matches

Returns a list of all parts of the text that match the pattern.

-- Find all numbers in text
say matches("I have 3 cats and 2 dogs", "\\d+")
-- ["3", "2"]

-- Find all email-like patterns
say matches("Contact alice@test.com or bob@test.com", "\\w+@\\w+\\.\\w+")
-- ["alice@test.com", "bob@test.com"]

matchesPattern(text, pattern) — Test if text matches

Returns yes or no based on whether the text matches the pattern.

say matchesPattern("hello123", "\\d+")   -- true (contains digits)
say matchesPattern("hello", "\\d+")      -- false (no digits)

replacePattern(text, pattern, replacement)

Replaces all matches of a pattern with the replacement text.

-- Remove all digits
say replacePattern("abc123def456", "\\d+", "")
-- "abcdef"

System & Environment

Interact with the operating system, run commands, and access environment variables.

env(key) / setEnv(key, value) — Environment variables

Read and set environment variables. These are settings stored by your operating system.

say env("HOME")       -- "/Users/alice"
say env("PATH")       -- your system PATH
setEnv("MY_APP", "production")

args() — Command-line arguments

Returns a list of arguments passed to your program.

-- If you run: quill run app.quill hello world
say args()   -- ["hello", "world"]

run(command) — Run a shell command

Runs a command on your computer and returns the output as text.

say run("date")           -- current date from the system
say run("ls")             -- list files in current directory
say run("whoami")         -- your username

runAsync(command) — Run command in background

Like run but doesn't block your program while waiting.

output is await runAsync("curl https://api.example.com")
say output

platform() / cpuCount() / memory()

say platform()    -- "darwin" (macOS), "linux", or "win32"
say cpuCount()     -- 8
say memory()       -- {total: 17179869184, free: 5368709120}

exit(code) — Stop the program

if somethingWrong:
  say "Fatal error!"
  exit(1)   -- exit with error code

wait(ms) — Pause execution

say "Starting..."
wait(2000)   -- pause for 2 seconds
say "Done!"

Concurrency

Run multiple tasks at the same time for better performance.

parallel(...functions) — Run tasks simultaneously

Runs multiple functions at the same time and waits for all of them to finish. Returns a list of results.

-- Fetch multiple URLs at once instead of one by one
results is await parallel(
  with: fetchJSON("https://api.example.com/users"),
  with: fetchJSON("https://api.example.com/posts")
)

race(...functions) — First one wins

Runs multiple functions and returns the result of whichever finishes first.

delay(ms) — Async pause

Pauses for a number of milliseconds without blocking (unlike wait).

await delay(1000)   -- wait 1 second

Templates

template(text, data) — Fill in placeholders

Replaces {{key}} placeholders in text with values from a data object. Great for generating emails, HTML, or any text with dynamic content.

msg is template("Hello, {{name}}! You have {{count}} messages.", {
  name: "Alice",
  count: 5
})
say msg   -- "Hello, Alice! You have 5 messages."

Database (SQLite)

Store and query data using SQLite, a simple file-based database. Requires the better-sqlite3 npm package (quill add better-sqlite3).

openDB(path) / closeDB(db)

db is openDB("mydata.db")
-- ... use the database ...
closeDB(db)

execute(db, sql, params) — Run a command

execute(db, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)", [])
execute(db, "INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 30])

query(db, sql, params) — Fetch data

users is query(db, "SELECT * FROM users WHERE age > ?", [18])
for each user in users:
  say user.name + " is " + toText(user.age)

Recipes

Common tasks showing how to combine multiple functions together.

Recipe: Process a list of names
names are ["  alice  ", "BOB", "  Charlie "]

-- Clean up, capitalize, sort, and display
cleaned is names
  | map_list(with n: trim(n))
  | map_list(with n: capitalize(lower(n)))
  | sort

say join(cleaned, ", ")   -- "Alice, Bob, Charlie"
Recipe: Read and process a CSV file
-- Read a CSV file and get the data
raw is read("data.csv")
rows is lines(raw)
headers is split(rows[0], ",")

say "Columns: " + join(headers, ", ")
say "Total rows: " + toText(length(rows) - 1)
Recipe: Simple REST API
users are []

server is createServer()

server.get("/api/users", users)

server.post("/api/users", with req, res:
  push(users, {id: uuid(), name: "New User"})
  give back {status: "created"}
)

server.listen(3000)
say "API running on http://localhost:3000"
Recipe: File backup script
-- Back up all .quill files to a backup folder
makeDir("backup")
files is listFiles(".")
quillFiles is filter(files, with f: endsWith(f, ".quill"))

for each file in quillFiles:
  copyFile(file, joinPath("backup", file))
  say "Backed up: " + file

say "Done! Backed up " + toText(length(quillFiles)) + " files"