Pico Documentation

Pico is a flat file CMS, this means there is no administration backend or database to deal with.
You simply create .md files in the “content” folder and that becomes a page.


Installing Pico is dead simple - and done in seconds! If you have access to a shell on your server (i.e. SSH access), we recommend using Composer. If not, use a pre-bundled release. If you don’t know what “SSH access” is, head over to the pre-bundled release. 😇

Pico requires PHP 5.3.6+ and the PHP extensions dom and mbstring to be enabled.

I want to use Composer

Starting with Pico 2.0 we recommend installing Pico using Composer whenever possible. Trust us, you won’t regret it when it comes to upgrading Pico! Anyway, if you don’t want to use Composer, or if you simply can’t use Composer because you don’t have access to a shell on your server, don’t despair, installing Pico using a pre-bundled release is still easier than everything you know!

Step 1

Open a shell and navigate to the httpdocs directory (e.g. /var/www/html) of your server. Download Composer and run it with the create-project option to install it to the desired directory (e.g. /var/www/html/pico):

$ curl -sSL https://getcomposer.org/installer | php
$ php composer.phar create-project picocms/pico-composer pico

Step 2

What second step? There’s no second step. That’s it! Open your favorite web browser and navigate to your brand new, stupidly simple, blazing fast, flat file CMS! Pico’s sample contents will explain how to create your own contents. 😊

I want to use a pre-bundled release

Do you know the feeling: You want to install a new website, so you upload all files of your favorite CMS and run the setup script - just to find out that you forgot about creating the SQL database first? Later the setup script tells you that the file permissions are wrong. Heck, what does this even mean? Forget about it, Pico is different!

Step 1

Download the latest Pico release and upload all files to the desired install directory of Pico within the httpdocs directory (e.g. /var/www/html/pico) of your server.

Step 2

Okay, here’s the catch: There’s no catch. That’s it! Open your favorite web browser and navigate to your brand new, stupidly simple, blazing fast, flat file CMS! Pico’s sample contents will explain how to create your own contents. 😊

I want to manage my website using a Git repository

Git is a very powerful distributed version-control system - and it can be used to establish a nice workflow around your Pico website. Using a Git repository for your website aids content creation and deployment, including collaborative editing and version control. If you want to manage your website in a Git repository, you use a Composer-based installation.

  1. Fork Pico’s Composer starter project using GitHub’s fork button. If you don’t want to use GitHub you aren’t required to, you can choose whatever Git server you want. Forking manually just requires some extra steps: First clone the Git repository locally, add your Git server as a remote and push the repository to this new remote.

  2. Clone your fork locally and add your contents and assets. You can edit Pico’s composer.json to include 3rd-party plugins and themes, or simply add your own plugins and themes to Pico’s plugins resp. themes directories. Don’t forget to commit your changes and push them to your Git server.

  3. Open a shell on your webserver and navigate to the httpdocs directory (e.g. /var/www/html). Download Composer, clone your Git repository to the desired directory (e.g. /var/www/html/pico) and install Pico’s dependencies using Composer’s install option:

     $ curl -sSL https://getcomposer.org/installer | php
     $ git clone https://github.com/<YOUR_USERNAME>/<YOUR_REPOSITORY> pico
     $ php composer.phar --working-dir=pico install
  4. If you update your website’s contents, simply commit your changes and push them to your Git server. Open a shell on your webserver and navigate to Pico’s install directory within the httpdocs directory (e.g. /var/www/html/pico) of your server. Pull all changes from your Git server and update Pico’s dependencies using Composer’s update option:

     $ git pull
     $ php composer.phar update

I’m a developer

So, you’re one of these amazing folks making all of this possible? We love you guys! As a developer we recommend you to clone Pico’s Git repository as well as the Git repositories of Pico’s default theme and the PicoDeprecated plugin. You can set up your workspace using Pico’s Composer starter project and include all of Pico’s components using local packages.

Using Pico’s Git repositories is different from using one of the installation methods elucidated above. It gives you the current development version of Pico, what is likely unstable and not ready for production use!

  1. Open a shell and navigate to the desired directory of Pico’s development workspace within the httpdocs directory (e.g. /var/www/html/pico) of your server. Download and extract Pico’s Composer starter project into the workspace directory:

     $ curl -sSL https://github.com/picocms/pico-composer/archive/master.tar.gz | tar xz
     $ mv pico-composer-master workspace
  2. Clone the Git repositories of all Pico components (Pico’s core, Pico’s default theme and the PicoDeprecated plugin) into the components directory:

     $ mkdir components
     $ git clone https://github.com/picocms/Pico.git components/pico
     $ git clone https://github.com/picocms/pico-theme.git components/pico-theme
     $ git clone https://github.com/picocms/pico-deprecated.git components/pico-deprecated
  3. Instruct Composer to use the local Git repositories as replacement for the picocms/pico (Pico’s core), picocms/pico-theme (Pico’s default theme) and picocms/pico-deprecated (the PicoDeprecated plugin) packages. Update the composer.json of your development workspace (i.e. workspace/composer.json) accordingly:

         "repositories": [
                 "type": "path",
                 "url": "../components/pico",
                 "options": { "symlink": true }
                 "type": "path",
                 "url": "../components/pico-theme",
                 "options": { "symlink": true }
                 "type": "path",
                 "url": "../components/pico-deprecated",
                 "options": { "symlink": true }
         "require": {
             "picocms/pico": "dev-master",
             "picocms/pico-theme": "dev-master",
             "picocms/pico-deprecated": "dev-master",
             "picocms/composer-installer": "^1.0"
  4. Download Composer and run it with the install option:

     $ curl -sSL https://getcomposer.org/installer | php
     $ php composer.phar --working-dir=workspace install

You can now open your web browser and navigate to Pico’s development workspace. All changes you make to Pico’s components will automatically be reflected in the development workspace.

By the way, you can also find all of Pico’s components on Packagist.org: Pico’s core, Pico’s default theme, the PicoDeprecated plugin and Pico’s Composer starter project.

Upgrade Learn more…

Do you remember when you installed Pico? It was ingeniously simple, wasn’t it? Upgrading Pico is no difference! The upgrade process differs depending on whether you used Composer or a pre-bundled release to install Pico. Please note that you should always create a backup of your Pico installation before upgrading!

Pico follows Semantic Versioning 2.0 and uses version numbers like MAJOR.MINOR.PATCH. When we update the PATCH version (e.g. 2.0.0 to 2.0.1), we made backwards-compatible bug fixes. If we change the MINOR version (e.g. 2.0 to 2.1), we added functionality in a backwards-compatible manner. Upgrading Pico is dead simple in both cases. Simply head over to the appropriate Upgrade sections below.

But wait, we forgot to mention what happens when we update the MAJOR version (e.g. 2.0 to 3.0). In this case we made incompatible API changes. We will then provide a appropriate upgrade tutorial, so please head over to the “Upgrade” page.

I’ve used Composer to install Pico

Upgrading Pico is dead simple if you’ve used Composer to install Pico. Simply open a shell and navigate to Pico’s install directory within the httpdocs directory (e.g. /var/www/html/pico) of your server. You can now upgrade Pico using just a single command:

$ php composer.phar update

That’s it! Composer will automatically update Pico and all plugins and themes you’ve installed using Composer. Please make sure to manually update all plugins and themes you’ve installed manually.

I’ve used a pre-bundled release to install Pico

Okay, installing Pico was easy, but upgrading Pico is going to be hard, isn’t it? I’m affraid I have to disappoint you… It’s just as simple as installing Pico!

First you’ll have to delete the vendor directory of your Pico installation (e.g. if you’ve installed Pico to /var/www/html/pico, delete /var/www/html/pico/vendor). Then download the latest Pico release and upload all files to your existing Pico installation directory. You will be prompted whether you want to overwrite files like index.php, .htaccess, … - simply hit “Yes”.

That’s it! Now that Pico is up-to-date, you need to update all plugins and themes you’ve installed.

I’m a developer

As a developer you should know how to stay up-to-date… 😉 For the sake of completeness, if you want to upgrade Pico, simply open a shell and navigate to Pico’s development workspace (e.g. /var/www/html/pico). Then pull the latest commits from the Git repositories of Pico’s core, Pico’s default theme and the PicoDeprecated plugin. Let Composer update your dependencies and you’re ready to go.

$ git -C components/pico pull
$ git -C components/pico-theme pull
$ git -C components/pico-deprecated pull
$ php composer.phar --working-dir=workspace update

Creating Content

Pico is a flat file CMS. This means there is no administration backend or database to deal with. You simply create .md files in the content folder and those files become your pages. For example, creating a file called index.md will make it show as your main landing page.

When you install Pico, it comes with some sample contents that will display until you add your own content. Simply add some .md files to your content folder in Pico’s root directory. No configuration is required, Pico will automatically use the content folder as soon as you create your own index.md. Just check out Pico’s sample contents for an example!

If you create a folder within the content directory (e.g. content/sub) and put an index.md inside it, you can access that folder at the URL https://example.com/pico/?sub. If you want another page within the sub folder, simply create a text file with the corresponding name and you will be able to access it (e.g. content/sub/page.md is accessible from the URL https://example.com/pico/?sub/page). Below we’ve shown some examples of locations and their corresponding URLs:

Physical Location URL
content/index.md /
content/sub.md ?sub (not accessible, see below)
content/sub/index.md ?sub (same as above)
content/sub/page.md ?sub/page
content/theme.md ?theme (hidden in menu)
content/a/very/long/url.md ?a/very/long/url

If a file cannot be found, the file content/404.md will be shown. You can add 404.md files to any directory. So, for example, if you wanted to use a special error page for your blog, you could simply create content/blog/404.md.

Pico strictly separates contents of your website (the Markdown files in your content directory) and how these contents should be displayed (the Twig templates in your themes directory). However, not every file in your content directory might actually be a distinct page. For example, some themes (including Pico’s default theme) use some special “hidden” file to manage meta data (like _meta.md in Pico’s sample contents). Some other themes use a _footer.md to represent the contents of the website’s footer. The common point is the _: all files and directories prefixed by a _ in your content directory are hidden. These pages can’t be accessed from a web browser, Pico will show a 404 error page instead.

As a common practice, we recommend you to separate your contents and assets (like images, downloads, etc.). We even deny access to your content directory by default. If you want to use some assets (e.g. a image) in one of your content files, files, use Pico’s assets folder. You can then access them in your Markdown using the %assets_url% placeholder, for example: ![Image Title](%assets_url%/image.png)

Text File Markup

Text files are marked up using Markdown and Markdown Extra. They can also contain regular HTML.

At the top of text files you can place a block comment and specify certain meta attributes of the page using YAML (the “YAML header”). For example:

Title: Welcome
Description: This description will go in the meta description tag
Author: Joe Bloggs
Date: 2001-04-25
Robots: noindex,nofollow
Template: index

These values will be contained in the {{ meta }} variable in themes (see below). Meta headers can sometimes have special functions. For example:

  • Date tells Pico when the page was created, letting you sort your pages not just alphabetically, but by date.
  • Template controls what Twig template Pico uses to display the page. For example, if you add Template: blog, Pico uses blog.twig.

You can create your own meta attributes and use them in your content or when modifying a theme. For example, if you create an Order attribute, you can set pages_order_by_meta: Order and pages_order_by: meta in config.yml to sort pages in the navigation menu in a custom order.

In an attempt to separate contents and styling, we recommend you to not use inline CSS in your Markdown files. You should rather add appropriate CSS classes to your theme. For example, you might want to add some CSS classes to your theme to rule how much of the available space a image should use (e.g. img.small { width: 80%; }). You can then use these CSS classes in your Markdown files, for example: ![Image Title](%assets_url%/image.png) {.small}

There are also certain variables that you can use in your text files:

  • %site_title% - The title of your Pico site
  • %base_url% - The URL to your Pico site; internal links can be specified using %base_url%?sub/page
  • %theme_url% - The URL to the currently used theme
  • %assets_url% - The URL to Pico’s assets directory
  • %themes_url% - The URL to Pico’s themes directory; don’t confuse this with %theme_url%
  • %plugins_url% - The URL to Pico’s plugins directory
  • %version% - Pico’s current version string (e.g. 2.0.0)
  • %meta.*% - Access any meta variable of the current page, e.g. %meta.author% is replaced with Joe Bloggs
  • %config.*% - Access any scalar config variable, e.g. %config.theme% is replaced with default


Pico is not blogging software - but makes it very easy for you to use it as a blog. You can find many plugins out there implementing typical blogging features like authentication, tagging, pagination and social plugins. See the below Plugins section for details.

If you want to use Pico as a blogging software, you probably want to do something like the following:

  1. Put all your blog articles in a separate blog folder in your content directory. All these articles should have a Date meta header.
  2. Create a blog.md or blog/index.md in your content directory. Add Template: blog-index to the YAML header of this page. It will later show a list of all your blog articles (see step 3).
  3. Create the new Twig template blog-index.twig (the file name must match the Template meta header from Step 2) in your theme directory. This template probably isn't very different from your default index.twig (i.e. copy index.twig), it will create a list of all your blog articles. Add the following Twig snippet to blog-index.twig near {{ content }}:
    {% for page in pages("blog")|sort_by("time")|reverse if not page.hidden %}
        <div class="post">
            <h3><a href="{{ page.url }}">{{ page.title }}</a></h3>
            <p class="date">{{ page.date_formatted }}</p>
            <p class="excerpt">{{ page.description }}</p>
    {% endfor %}


Pico is highly customizable in two different ways: On the one hand you can change Pico’s appearance by using themes, on the other hand you can add new functionality by using plugins. Doing the former includes changing Pico’s HTML, CSS and JavaScript, the latter mostly consists of PHP programming.

This is all Greek to you? Don’t worry, you don’t have to spend time on these techie talk - it’s very easy to use one of the great themes or plugins others developed and released to the public. Please refer to the next sections for details.


You can create themes for your Pico installation in the themes folder. Pico uses Twig for template rendering. You can select your theme by setting the theme option in config/config.yml to the name of your theme folder.

Pico’s default theme isn’t really intended to be used for a productive website, it’s rather a starting point for creating your own theme. If the default theme isn’t sufficient for you, and you don’t want to create your own theme, you can use one of the great themes third-party developers and designers created in the past. As with plugins, you can find themes on our themes page.

All themes must include an index.twig file to define the HTML structure of the theme, and a pico-theme.yml to set the necessary config parameters. Just refer to Pico’s default theme as an example. You can use different templates for different content files by specifying the Template meta header. Simply add e.g. Template: blog to the YAML header of a content file and Pico will use the blog.twig template in your theme folder to display the page.

Below are the Twig variables that are available to use in themes. Please note that URLs (e.g. {{ base_url }}) never include a trailing slash.

  • {{ site_title }} - Shortcut to the site title (see config/config.yml)
  • {{ config }} - Contains the values you set in config/config.yml (e.g. {{ config.theme }} becomes default)
  • {{ base_url }} - The URL to your Pico site; use Twig’s link filter to specify internal links (e.g. {{ "sub/page"|link }}), this guarantees that your link works whether URL rewriting is enabled or not
  • {{ theme_url }} - The URL to the currently active theme
  • {{ assets_url }} - The URL to Pico’s assets directory
  • {{ themes_url }} - The URL to Pico’s themes directory; don’t confuse this with {{ theme_url }}
  • {{ plugins_url }} - The URL to Pico’s plugins directory
  • {{ version }} - Pico’s current version string (e.g. 2.0.0)
  • {{ meta }} - Contains the meta values of the current page
    • {{ meta.title }} - The Title YAML header
    • {{ meta.description }} - The Description YAML header
    • {{ meta.author }} - The Author YAML header
    • {{ meta.date }} - The Date YAML header
    • {{ meta.date_formatted }} - The formatted date of the page as specified by the date_format parameter in your config/config.yml
    • {{ meta.time }} - The Unix timestamp derived from the Date YAML header
    • {{ meta.robots }} - The Robots YAML header
  • {{ content }} - The content of the current page after it has been processed through Markdown
  • {{ previous_page }} - The data of the previous page, relative to current_page
  • {{ current_page }} - The data of the current page; refer to the “Pages” section below for details
  • {{ next_page }} - The data of the next page, relative to current_page

To call assets from your theme, use {{ theme_url }}. For instance, to include the CSS file themes/my_theme/example.css, add <link rel="stylesheet" href="{{ theme_url }}/example.css" type="text/css" /> to your index.twig. This works for arbitrary files in your theme’s folder, including images and JavaScript files.

Please note that Twig escapes HTML in all strings before outputting them. So for example, if you add headline: My <strong>favorite</strong> color to the YAML header of a page and output it using {{ meta.headline }}, you’ll end up seeing My <strong>favorite</strong> color - yes, including the markup! To actually get it parsed, you must use {{ meta.headline|raw }} (resulting in the expected My favorite color). Notable exceptions to this are Pico’s content variable (e.g. {{ content }}), Pico’s content filter (e.g. {{ "sub/page"|content }}), and Pico’s markdown filter, they all are marked as HTML safe.

Dealing with pages

There are several ways to access Pico’s pages list. You can access the current page’s data using the current_page variable, or use the prev_page and/or next_page variables to access the respective previous/next page in Pico’s pages list. But more importantly there’s the pages() function. No matter how you access a page, it will always consist of the following data:

  • {{ id }} - The relative path to the content file (unique ID)
  • {{ url }} - The URL to the page
  • {{ title }} - The title of the page (Title YAML header)
  • {{ description }} - The description of the page (Description YAML header)
  • {{ author }} - The author of the page (Author YAML header)
  • {{ date }} - The date of the page (Date YAML header)
  • {{ date_formatted }} - The formatted date of the page as specified by the date_format parameter in your config/config.yml
  • {{ time }} - The Unix timestamp derived from the page’s date
  • {{ raw_content }} - The raw, not yet parsed contents of the page; use the filter to get the parsed contents of a page by passing its unique ID (e.g. {{ "sub/page"|content }})
  • {{ meta }} - The meta values of the page (see global {{ meta }} above)
  • {{ prev_page }} - The data of the respective previous page
  • {{ next_page }} - The data of the respective next page
  • {{ tree_node }} - The page’s node in Pico’s page tree; check out Pico’s page tree documentation for details

Pico’s pages() function is the best way to access all of your site’s pages. It uses Pico’s page tree to easily traverse a subset of Pico’s pages list. It allows you to filter pages and to build recursive menus (like dropdowns). By default, pages() returns a list of all main pages (e.g. content/page.md and content/sub/index.md, but not content/sub/page.md or content/index.md). If you want to return all pages below a specific folder (e.g. content/blog/), pass the folder name as first parameter to the function (e.g. pages("blog")). Naturally you can also pass variables to the function. For example, to return a list of all child pages of the current page, use pages(current_page.id). Check out the following code snippet:

<section class="articles">
    {% for page in pages(current_page.id) if not page.hidden %}
            <h2><a href="{{ page.url }}">{{ page.title }}</a></h2>
            {{ page.id|content }}
    {% endfor %}

The pages() function is very powerful and also allows you to return not just a page’s child pages by passing the depth and depthOffset params. For example, if you pass pages(depthOffset=-1), the list will also include Pico’s main index page (i.e. content/index.md). This one is commonly used to create a theme’s main navigation. If you want to learn more, head over to Pico’s complete pages() function documentation.

If you want to access the data of a particular page, use Pico’s pages variable. Just take content/_meta.md in Pico’s sample contents for an example: content/_meta.md contains some meta data you might want to use in your theme. If you want to output the page’s tagline meta value, use {{ pages["_meta"].meta.logo }}. Don’t ever try to use Pico’s pages variable as an replacement for Pico’s pages() function. Its usage looks very similar, it will kinda work and you might even see it being used in old themes, but be warned: It slows down Pico. Always use Pico’s pages() function when iterating Pico’s page list instead (e.g. {% for page in pages() %}…{% endfor %}).

Twig filters and functions

Additional to Twig’s extensive list of filters, functions and tags, Pico also provides some useful additional filters and functions to make theming even easier.

  • Pass the unique ID of a page to the link filter to return the page’s URL (e.g. {{ "sub/page"|link }} gets https://example.com/pico/?sub/page).
  • You can replace URL placeholders (like %base_url%) in arbitrary strings using the url filter. This is helpful together with meta variables, e.g. if you add image: %assets_url%/stock.jpg to the YAML header of a page, {{ meta.image|url }} will return https://example.com/pico/assets/stock.jpg.
  • To get the parsed contents of a page, pass its unique ID to the content filter (e.g. {{ "sub/page"|content }}).
  • You can parse any Markdown string using the markdown filter. For example, you might use Markdown in the description meta variable and later parse it in your theme using {{ meta.description|markdown }}. You can also pass meta data as parameter to replace %meta.*% placeholders (e.g. {{ "Written by *%meta.author%*"|markdown(meta) }} yields “Written by John Doe”). However, please note that all contents will be wrapped inside HTML paragraph elements (i.e. <p>…</p>). If you want to parse just a single line of Markdown markup, pass the singleLine param to the markdown filter (e.g. {{ "This really is a *single* line"|markdown(singleLine=true) }}).
  • Arrays can be sorted by one of its keys using the sort_by filter (e.g. {% for page in pages|sort_by([ 'meta', 'nav' ]) %}...{% endfor %} iterates through all pages, ordered by the nav meta header; please note the [ 'meta', 'nav' ] part of the example, it instructs Pico to sort by page.meta.nav). Items which couldn’t be sorted are moved to the bottom of the array; you can specify bottom (move items to bottom; default), top (move items to top), keep (keep original order) or remove (remove items) as second parameter to change this behavior.
  • You can return all values of a given array key using the map filter (e.g. {{ pages|map("title") }} returns all page titles).
  • Use the url_param and form_param Twig functions to access HTTP GET (i.e. a URL’s query string like ?some-variable=my-value) and HTTP POST (i.e. data of a submitted form) parameters. This allows you to implement things like pagination, tags and categories, dynamic pages, and even more - with pure Twig! Simply head over to our introductory page for accessing HTTP parameters for details.


Plugins for users

Officially tested plugins can be found at https://picocms.org/plugins/, but there are many awesome third-party plugins out there! A good start point for discovery is our Wiki.

Pico makes it very easy for you to add new features to your website using plugins. Just like Pico, you can install plugins either using Composer (e.g. composer require phrozenbyte/pico-file-prefixes), or manually by uploading the plugin’s file (just for small plugins consisting of a single file, e.g. PicoFilePrefixes.php) or directory (e.g. PicoFilePrefixes) to your plugins directory. We always recommend you to use Composer whenever possible, because it makes updating both Pico and your plugins way easier. Anyway, depending on the plugin you want to install, you may have to go through some more steps (e.g. specifying config variables) to make the plugin work. Thus you should always check out the plugin’s docs or README.md file to learn the necessary steps.

Plugins which were written to work with Pico 1.0 and later can be enabled and disabled through your config/config.yml. If you want to e.g. disable the PicoDeprecated plugin, add the following line to your config/config.yml: PicoDeprecated.enabled: false. To force the plugin to be enabled, replace false by true.

Plugins for developers

You’re a plugin developer? We love you guys! You can find tons of information about how to develop plugins at https://picocms.org/development/. If you’ve developed a plugin before and want to upgrade it to Pico 2.0, refer to the upgrade section of the docs.


Configuring Pico really is stupidly simple: Just create a config/config.yml to override the default Pico settings (and add your own custom settings). Take a look at the config/config.yml.template for a brief overview of the available settings and their defaults. To override a setting, simply copy the line from config/config.yml.template to config/config.yml and set your custom value.

But we didn’t stop there. Rather than having just a single config file, you can use a arbitrary number of config files. Simply create a .yml file in Pico’s config dir and you’re good to go. This allows you to add some structure to your config, like a separate config file for your theme (config/my_theme.yml).

Please note that Pico loads config files in a special way you should be aware of. First of all it loads the main config file config/config.yml, and then any other *.yml file in Pico’s config dir in alphabetical order. The file order is crucial: Config values which have been set already, cannot be overwritten by a succeeding file. For example, if you set site_title: Pico in config/a.yml and site_title: My awesome site! in config/b.yml, your site title will be “Pico”.

Since YAML files are plain text files, users might read your Pico config by navigating to https://example.com/pico/config/config.yml. This is no problem in the first place, but might get a problem if you use plugins that require you to store security-relevant data in the config (like credentials). Thus you should always make sure to configure your webserver to deny access to Pico’s config dir. Just refer to the “URL Rewriting” section below. By following the instructions, you will not just enable URL rewriting, but also deny access to Pico’s config dir.

URL Rewriting

Pico’s default URLs (e.g. https://example.com/pico/?sub/page) already are very user-friendly. Additionally, Pico offers you a URL rewrite feature to make URLs even more user-friendly (e.g. https://example.com/pico/sub/page). Below you’ll find some basic info about how to configure your webserver proberly to enable URL rewriting. For additional assistance, please refer to the “Getting Help” section below.


If you’re using the Apache web server, URL rewriting should be enabled automatically. If URL rewriting doesn’t work (you’re getting 404 Not Found error messages from Apache), please make sure to enable the mod_rewrite module and to enable .htaccess overrides. You might have to set the AllowOverride directive to AllowOverride All in your virtual host config file or global httpd.conf/apache.conf. Assuming rewritten URLs work, but Pico still shows no rewritten URLs, force URL rewriting by setting rewrite_url: true in your config/config.yml. If you rather get a 500 Internal Server Error no matter what you do, try removing the Options directive from Pico’s .htaccess file (it’s the last line).

Nginx Learn more…

If you’re using Nginx, you can use the following config to enable URL rewriting (lines 5 to 8) and denying access to Pico’s internal files (lines 1 to 3). You’ll need to adjust the path (/pico on lines 1, 2, 5 and 7) to match your installation directory. Additionally, you’ll need to enable URL rewriting by setting rewrite_url: true in your config/config.yml. The Nginx config should provide the bare minimum you need for Pico. Nginx is a very extensive subject. If you have any trouble, please read through our Nginx config docs.

location ~ ^/pico/((config|content|vendor|composer\.(json|lock|phar))(/|$)|(.+/)?\.(?!well-known(/|$))) {
    try_files /pico/index.php$is_args$args =404;

location /pico/ {
    index index.php;
    try_files $uri $uri/ /pico/index.php$is_args$args;


Pico runs smoothly on Lighttpd. You can use the following config to enable URL rewriting (lines 6 to 9) and denying access to Pico’s internal files (lines 1 to 4). Make sure to adjust the path (/pico on lines 2, 3 and 7) to match your installation directory, and let Pico know about available URL rewriting by setting rewrite_url: true in your config/config.yml. The config below should provide the bare minimum you need for Pico.

url.rewrite-once = (
    "^/pico/(config|content|vendor|composer\.(json|lock|phar))(/|$)" => "/pico/index.php",
    "^/pico/(.+/)?\.(?!well-known(/|$))" => "/pico/index.php"

url.rewrite-if-not-file = (
    "^/pico(/|$)" => "/pico/index.php"

Getting Help

Getting Help as a user

If you want to get started using Pico, please refer to the user docs (you’re reading them right now!). Please read the upgrade notes if you want to upgrade from Pico 1.0 to Pico 2.0.

Getting Help as a developer

If you’re a developer, please refer to the “Contributing” section below and our contribution guidelines. To get you started with creating a plugin or theme, please read the developer docs on our website.

You still need help or experience a problem with Pico?

When the docs can’t answer your question, you can get help by joining us on #picocms on Libera.Chat (logs). When you’re experiencing problems with Pico, please don’t hesitate to create a new Issue on GitHub. Concerning problems with plugins or themes, please refer to the website of the developer of this plugin or theme.

Before creating a new Issue, please make sure the problem wasn’t reported yet using GitHubs search engine. Please describe your issue as clear as possible and always include the Pico version you’re using. Provided that you’re using plugins, include a list of them too. We need information about the actual and expected behavior, the steps to reproduce the problem, and what steps you have taken to resolve the problem by yourself (i.e. your own troubleshooting).


You want to contribute to Pico? We really appreciate that! You can help make Pico better by contributing code or reporting issues, but please take note of our contribution guidelines. In general you can contribute in three different areas:

  1. Plugins & Themes: You’re a plugin developer or theme designer? We love you guys! You can find tons of information about how to develop plugins and themes at https://picocms.org/development/. If you have created a plugin, feel free to add it to our plugins wiki page. You may also Submit plugins and themes to our website, where they’ll be displayed on the official plugin or theme pages!

  2. Documentation: We always appreciate people improving our documentation. You can either improve the inline user docs or the more extensive user docs on our website. You can also improve the docs for plugin and theme developers. Simply fork our website’s Git repository from https://github.com/picocms/picocms.github.io, change the Markdown files and open a pull request.

  3. Pico’s Core: The supreme discipline is to work on Pico’s Core. Your contribution should help every Pico user to have a better experience with Pico. If this is the case, fork Pico from https://github.com/picocms/Pico and open a pull request. We look forward to your contribution!

By contributing to Pico, you accept and agree to the Developer Certificate of Origin for your present and future contributions submitted to Pico. Please refer to the “Developer Certificate of Origin” section in our CONTRIBUTING.md.

You don’t have time to contribute code to Pico, but still want to “stand a coffee” for the ones who do? You can contribute monetary to Pico using Bountysource, a crowd funding website that focuses on individual issues and feature requests. Just refer to the “Bounties and Fundraisers” section below for more info.

Bounties and Fundraisers

Pico uses Bountysource to allow monetary contributions to the project. Bountysource is a crowd funding website that focuses on individual issues and feature requests in Open Source projects using micropayment. Users, or “Backers”, can pledge money for fixing a specific issue, implementing new features, or developing a new plugin or theme. Open source software developers, or “Bounty Hunters”, can then pick up and solve these tasks to earn the money.

Obviously this won’t allow a developer to replace a full time job, it’s rather aiming to “stand a coffee”. However, it helps bringing users and developers closer together, and shows developers what users want and how much they care about certain things. Nevertheless you can still donate money to the project itself, as an easy way to say “Thank You” and to support Pico.

If you want to encourage developers to fix a specific issue or implement a feature, simply pledge a new bounty or back an existing one.

As a developer you can pick up a bounty by simply contributing to Pico (please refer to the “Contributing” section above). You don’t have to be a official Pico Contributor! Pico is a Open Source project, anyone can open pull requests and claim bounties.

Official Pico Contributors won’t claim bounties on their own behalf, Pico will never take any money out of Bountysource. All money collected by Pico is used to pledge new bounties or to support projects Pico depends on.

GitHub Pages - This page was generated from 9164cea2f254e611a1de2311775f6d0ee370c838 at 2022-08-10 21:26:48 +0000

Pico was made by Gilbert Pellegrom and is maintained by The Pico Community. Released under the MIT license.