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.
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)
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.
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"
-- 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)
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"
-- 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"