Project Structure
How a tulip project is organized and how each file is processed.
Directory layout
my-site/
tulip.toml # site configuration
layouts/ # shared layouts
main.tulip
pages/ # .tulip templates → HTML pages
index.tulip
about.tulip
blog/
post.tulip
components/ # reusable components
card.tulip
nav.tulip
content/ # markdown files with frontmatter
blog/
hello.md
static/ # copied as-is to output
css/
images/
plugins/ # JS plugins
seo/
plugin.toml
index.tstulip.toml
The configuration file at the root of every tulip project. It defines the site name, description, and feature flags:
[site]
name = "My Site"
description = "A personal blog"
[minify]
enabled = trueAll settings are optional. tulip works with just an empty tulip.toml file.
layouts/
Layouts define the outer HTML structure shared across pages. A layout uses @yield('content') to mark where page content is inserted:
<!DOCTYPE html>
<html>
<head>
<title>{{ site.name }}</title>
</head>
<body>
@yield('content')
</body>
</html>Pages extend a layout with @extends('layouts/main') and fill sections with @section / @endsection. You can have multiple layouts for different page types — landing pages, blog posts, documentation, etc.
pages/
Every .tulip file in pages/ becomes an HTML file. The directory structure is preserved in the output:
pages/index.tulip→dist/index.htmlpages/about.tulip→dist/about/index.htmlpages/blog/post.tulip→dist/blog/post/index.html
about.tulip generates about/index.html so URLs look like /about/ instead of /about.html.components/
Reusable template fragments that accept props and an optional slot. A component file defines a piece of markup:
<div class="card">
<h3>{{ title }}</h3>
{{ slot }}
</div>Use it from any page or layout with the @component directive:
@component('card', { title: "Hello" })
<p>Card body content goes here.</p>
@endcomponentcontent/
Markdown files with YAML frontmatter. Each .md file is rendered to HTML using the layout specified in its frontmatter:
---
title: Hello World
layout: layouts/main
---
# Hello World
This is rendered as HTML inside the layout.static/
Everything in static/ is copied directly to dist/ without any processing. Use it for:
- CSS files (when not using Tailwind)
- Images, fonts, and favicons
- JavaScript files
- Any other assets that should be served as-is
plugins/
JavaScript plugins that extend the build pipeline. Each plugin lives in its own directory with a plugin.toml manifest and an index.ts (or index.js) entry point:
plugins/seo/
plugin.toml # name, version, description, hooks
index.ts # plugin logicPlugins are executed by tulip's built-in JavaScript engine — no Node.js needed. Manage plugins with the CLI:
tulip plugin new <name>— scaffold a new plugintulip plugin add <github-url>— install from GitHubtulip plugin remove <name>— uninstall a plugintulip plugin list— show installed plugins