PHPackages                             skimpy/cms - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. skimpy/cms

ActiveLibrary

skimpy/cms
==========

Skimpy CMS

v0.3.0(1y ago)029[2 issues](https://github.com/skimpy/cms/issues)MITTwigPHP ^8.0.2

Since Jan 17Pushed 1y ago1 watchersCompare

[ Source](https://github.com/skimpy/cms)[ Packagist](https://packagist.org/packages/skimpy/cms)[ Docs](https://github.com/skimpy/cms)[ RSS](/packages/skimpy-cms/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (6)Dependencies (1)Versions (8)Used By (0)

 [![Latest Stable Version](https://camo.githubusercontent.com/3c76a59455c2eb691e19dfb64c7d58d6cad9800fa6e939eca580f2f05c310b07/68747470733a2f2f706f7365722e707567782e6f72672f736b696d70792f636d732f762f737461626c652e737667)](https://packagist.org/packages/skimpy/cms) [![License](https://camo.githubusercontent.com/2e3bab0403dbf910ee51747f3ff3b1e978adf3a92bb7ec60326fd075ce43dff5/68747470733a2f2f706f7365722e707567782e6f72672f736b696d70792f636d732f6c6963656e73652e737667)](https://packagist.org/packages/skimpy/cms)

About Skimpy
------------

[](#about-skimpy)

Skimpy is a file based CMS that is written with and runs on PHP (Lumen). It is NOT a static site generator. Generators are cumbersome tools. Skimpy is easy to use. You just create a file, and there it is! Skimpy is so easy to use that it might be the easiest CMS/blogging tool that you've ever tried. Don't believe me? Give it a shot!

Documentation
-------------

[](#documentation)

- [Introduction](#introduction)
- [Installation](#installation)
- [Creating a Blog Post](#creating-a-blog-post)
- [Adding Front Matter](#adding-front-matter)
- [Creating a Page](#creating-a-page)
- [Categorizing/Tagging Content](#categorizing-content)
- [Creating Page Types](#creating-page-types)
- [Index Pages](#index-pages)
- [URI Mapping &amp; Template Variables](#uri-mapping--template-variables)
- [Template Hierarchy](#template-hierarchy)
- [Custom Templates](#custom-templates)
- [How does Skimpy work?](#how-does-skimpy-work)

Introduction
------------

[](#introduction)

 Skimpy is a simple file based CMS that can be used to make a website or blog. Skimpy is built for developers, though anyone who can create files and put a PHP site on the internet can use it. Skimpy aims to be simple and easy to use.

Installation
============

[](#installation)

#### Server Requirements

[](#server-requirements)

- PHP &gt;= 8.0.2
- OpenSSL PHP Extension
- PDO PHP Extension
- Mbstring PHP Extension

#### Installing Skimpy via Composer

[](#installing-skimpy-via-composer)

 You can install Skimpy with Composer and run it with PHP's built in server or you can run it in a container with the built in Dockerfile.

#### Composer + PHP Server

[](#composer--php-server)

1. `composer create-project --prefer-dist skimpy/cms skimpy`
2. `cd path/to/skimpy`
3. `cp .env.example .env`
4. Update the .env file to match your preferences/info
5. `php -S localhost:4000 -t public`
6. Visit

#### Composer + Docker

[](#composer--docker)

1. `composer create-project --prefer-dist skimpy/cms skimpy`
2. `cd path/to/skimpy`
3. `cp .env.example .env`
4. Update the .env file to match your preferences/info
5. Build the Container
6. `docker build -t skimpy .`
7. Run the container with a volume so code changes are reflected
8. `docker run -p 4000:80 -v $PWD:/var/www/html skimpy`
9. Visit

Creating a Blog Post
--------------------

[](#creating-a-blog-post)

1. Create a new markdown file called `test-post.md` inside the `site/content` directory.
2. Visit `http://localhost:4000/test-post` and voila!
3. Add a markdown header to the file `# Test Header` and refresh. You'll see an h1 tag that reads "Test Header".

#### How URIs are determined

[](#how-uris-are-determined)

 In the example above where we created "test-post", you can see that Skimpy uses the filename as the URI to the post. If you put the file inside a directory "products" and name the file "widget.md". The URI to the file will be `/products/widget`

```
path = path/to/skimpy/site/content/products/widget.md
URL = http://localhost:4000/products/widget

```

Adding Front Matter
-------------------

[](#adding-front-matter)

 You can customize certain properties of an entry using front matter key values. All front matter is optional and Skimpy will use sensible defaults.

Always use exactly three hyphens "---" to separate front matter from content. Otherwise, you'll get an exception or your file won't parse correctly.

Keep in mind that using three hypens "---" on their own line, or at the end of the file without a new line, will cause Skimpy to assume it is the front matter separator whether that is what you intend or not.

 Native Front Matter Keys   Key Description     title Custom title if different from the filename   date The published date of the content. Always use PHP Y-m-d or Y-m-d H:i:s format. DATES MUST BE QUOTED "2020-01-22"   seoTitle The content to put in the head &lt;title&gt; tag   description The SEO meta description for this page (if any)   template The name of the template to use if not using whichever template matches the convention for this content type   categories The categories the content belongs to   tags The tags to assign to the content  #### Front Matter Metadata

[](#front-matter-metadata)

Any key/value you put in front matter that isn't built in will be stored as metadata.

You can access any custom front matter key values in your templates.

The "restaurants" key in the example file below is an example of metadata.

#### Accessing FrontMatter Metadata in Templates

[](#accessing-frontmatter-metadata-in-templates)

Call the "meta" method on the entry object and pass in the key you want.

```
{{ entry.meta('restaurants') }}
```

#### Example Content File With Front Matter

[](#example-content-file-with-front-matter)

```
title: My 2019 Trip to Germany
date: "2019-08-27"
description: The SEO meta description (if any) goes here
seoTitle: Custom SEO title here
categories: [Vacation]
tags: [Personal Growth]
restaurants: [Kin Dee, Markthalle Neun]
---
The content for the post goes here...

```

Creating a Page
---------------

[](#creating-a-page)

 Skimpy sites don't have to be blogs at all but it does make blogging easy if that's what you are doing. Before I explain "pages" in Skimpy, let's first define what a page is. Both pages and posts are just files that hold content for display when someone hits the matching URI. The only difference between a "page" and a "post" is that people don't typically display an index of pages like they do blog posts. Pages are not usually listed on the home screen with "excerpts" like blog posts and pages aren't really meant to be categorized or tagged.

 So if you would like to create an "entry" on your site that doesn't show up in your default blog feed, then you want to create a page. This is accomplished by creating a subdirectory under the content directory and placing any files that you want to be a "page" inside that directory. You can call the directory anything you want but keep in mind the directory name will be part of the URI to access the page.

 You may also exclude root entries from displaying on the home page or an index by manually changing the content type via the Front Matter "type" key. This essentially is the same as placing the file in a subdirectory. Any file inside a subdirectory has a "type" property with a value matching the name of the parent directory. Try and avoid using the "type" key if you can. Sites that follow the conventions will be more well organized and easier to navigate. You can always just make a "pages" directory and put your pages there. Having a URI segment "pages" precede the page URI really isn't a big deal.

Taxonomies - Categorizing &amp; Tagging Content
-----------------------------------------------

[](#taxonomies---categorizing--tagging-content)

Content can be categorized or tagged. Categories and tags are referred to as "taxonomies" (like in WordPress). Taxonomies are a way of classifying content. There are already two predefined taxonomies in the default Skimpy installation. And you guessed it, those taxonomies are categories and tags. If you wanted to add your own taxonomy, you would just copy the `categories.yaml` file and change the values.

Taxonomies have "terms". In the case of the "categories" taxonomy, the terms are the actual categories. You add new categories by adding a new array to the terms key in the `content/taxonomies/categories.yaml`file. You simply provide a name for the category and a slug to be used in the URI.

#### Public Terms Route

[](#public-terms-route)

 By default, Skimpy will list links to the terms (category names) you have defined in the `categories.yaml` file, when you visit `/categories`. If you want to turn this off for a particular taxonomy (like categories) then you should set the `has_public_terms_route` yaml key to `false` in `categories.yaml`.

#### Assigning Categories/Tags

[](#assigning-categoriestags)

You simply add the key `categories` to the YAML front matter of any content file and provide an array of category names. Use the actual "name" NOT the slug.

Don't forget the Front Matter separator! "---"

```
categories: [Web Development]
tags: [Tag 1]
date: "2020-01-21"
---
Your post content here...

```

Creating Page Types
-------------------

[](#creating-page-types)

Let's say you want to add a page for every person on your team and you want to list those people on your "team" page.

1. Create folder `content/team`
2. Create file `content/team/kevin-rose.md`
3. Create file `content/team/tim-ferriss.md`
4. Enable a "team index" by creating `content/team/index.md`
5. The following URLs are now valid

    - `example.com/team` - Lists links to any file under the "team" directory
    - `example.com/team/kevin-rose`
    - `example.com/team/tim-ferriss`

Index Pages
-----------

[](#index-pages)

Index pages are basically an archive of content files inside of a subdirectory of content.

See the example for [creating page types](#creating-page-types)

By default, there is no index for files inside a subfolder of the content directory. To turn the index uri on, in other words, to make the subfolder name a valid URI on your website, you just create a file inside the subdirectory called `index.md`

URI Mapping &amp; Template Variables
------------------------------------

[](#uri-mapping--template-variables)

There are three types of "entities" in Skimpy - `entry`, `taxonomy`, and `term`. The current URI determines what type of entity is queried and what the template variable names are. You can determine what file is being displayed just by looking at the URI. **The file structure maps directly to the current URI**. Just keep in mind when you create a taxonomy file, you are creating a URL that matches the name of that file. When you create a directory inside content and you place an index.md file in it, you are creating a URL that matches the path to that directory.

 URI Mapping   When URI Matches You'll See Template Variable     the name of a content file The files markdown content `entry`   the name of a taxonomy file (like "categories") A listing of links to the terms registered to the taxonomy `taxonomy`   the name of a term (like a category name) A listing of links to entries with that term assigned in their Front Matter `term`  Template Hierarchy
------------------

[](#template-hierarchy)

 Skimpy uses [Twig](https://twig.symfony.com/doc/2.x/) for templating. Please see the [Twig Docs](https://twig.symfony.com/doc/2.x/) to discover all the power of Twig.

Which template is used depends on the type of entity (entry, taxonomy, term) being displayed. You can manually set the template with the `template` front matter key

1. FrontMatter key `template: your-template-name`
2. The parent folder name if the file is in a subdirectory of content
3. If the file is an index (index.md), the index template.
4. The entity type (entry = entry.twig, taxonomy = taxonomy.twig, term = term.twig)

Custom Templates
----------------

[](#custom-templates)

 Skimpy uses [Twig](https://twig.symfony.com/doc/2.x/) for templating. Please see the [Twig Docs](https://twig.symfony.com/doc/2.x/) to discover all the power of Twig.

 Skimpy [has some conventions](#template-hierarchy) for deciding what template to use. You can override the conventions by adding a `template` key to the front matter of a content file.

#### Using a custom template

[](#using-a-custom-template)

1. Create the template `site/templates/my-custom-template.twig`
2. Open or create a content file and set the template in the Front Matter.
     `template: my-custom-template`

Deployment
----------

[](#deployment)

 Deploying Skimpy to production is easy. Just make sure your server meets the [server requirements](#server-requirements) and create a virtual host with the document root set to the skimpy public folder.

#### Auto Rebuild

[](#auto-rebuild)

 What is auto rebuild? Auto rebuild refers to Skimpy scanning your content folder and updating the SQLite DB on every request to your website. This makes development quick and easy. You don't have to worry about "generating" your website. You can turn this feature on or off in your local or production environment. I wouldn't really worry about it too much because it's not going to make much of a difference. That being said I will share my preferred way of deploying with Skimpy.

#### How I Deploy Skimpy

[](#how-i-deploy-skimpy)

1. I track my SQLite DB with Git so it gets automatically deployed when I push to master. This allows my Skimpy sites to be updated to latest when I push to master without the production sites having to rebuild the database on each request
2. I set `AUTO_REBUILD=false` in my `.env` file **on the production site** so the database won't be rebuilt on every request.

How does Skimpy work?
---------------------

[](#how-does-skimpy-work)

 When a request hits your website, Skimpy scans all of the files in your `site/content` directory, converts them to [Doctrine](https://www.doctrine-project.org/) entities, and shoves them into an sqlite database. You don't have to pay any attention to the database at all if you don't want. The reason Skimpy converts your content into database records is so that it can take advantage of all of the power of doctrine and SQL in general. The database component in Skimpy is used more like a cache. You should never be editing your database directly as Skimpy will just wipe out any changes you made automatically the next time your website receives a request.

 Skimpy uses Doctrine and a database for several reasons. The primary reason for the DB is so that you don't have to "generate" your actual website everytime you make changes to your content, or run a "watch" command that generates the changes when you save a file. Doing things the "generater way" is just nonsense. Generating adds complexity to creating a website or blog. Writing and adding content should be mindless and that's what Skimpy sets out to accomplish.

License
-------

[](#license)

Skimpy CMS is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance32

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~269 days

Recently: every ~402 days

Total

7

Last Release

700d ago

PHP version history (2 changes)v0.1.0PHP ^7.2

v0.2.0PHP ^8.0.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/d2e6d51f82538c6124aca2582c2d81d2577a879340a709580be5e6836a5dc789?d=identicon)[jtallant](/maintainers/jtallant)

---

Top Contributors

[![jtallant](https://avatars.githubusercontent.com/u/857110?v=4)](https://github.com/jtallant "jtallant (35 commits)")

---

Tags

cmsblogflat-file cmsskimpyflat file blog

### Embed Badge

![Health badge](/badges/skimpy-cms/health.svg)

```
[![Health](https://phpackages.com/badges/skimpy-cms/health.svg)](https://phpackages.com/packages/skimpy-cms)
```

###  Alternatives

[roots/wordpress

WordPress is open source software you can use to create a beautiful website, blog, or app.

19116.9M258](/packages/roots-wordpress)[johnpbloch/wordpress-core

WordPress is open source software you can use to create a beautiful website, blog, or app.

17812.3M117](/packages/johnpbloch-wordpress-core)[forkcms/forkcms

Fork is an open source CMS that will rock your world.

1.2k44.5k](/packages/forkcms-forkcms)[roots/wordpress-no-content

WordPress is open source software you can use to create a beautiful website, blog, or app.

1812.6M30](/packages/roots-wordpress-no-content)[serverfireteam/blog

A nice blog system with laravel and laravelpanel

523.1k](/packages/serverfireteam-blog)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
