The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


App::Skeletor - Bootstrap a new project from a shared template


From the commandline:

    skeletor --template Skeltor::Template::Example \
      --as Local::MyApp \
      --directory ~/new_projects \
      --author 'John Napiorkowski <>' \
      --year 2015

Bootstrap from URL hosted version:

    curl -L | perl - \
      --template Skeletor::Template::Example \
      --as Local::MyApp \
      --author 'test author'

(Assumes you have `curl` installed, as it is on many modern unix-like systems).


When initially setting up a project (like a website build using Catalyst or an application that uses DBIx::Class) there is often a number of boilerplate files and directories you need to create before beginning the true work of application building. Additionally, during general development certain types of repeated tasks may occur which would benefit from automation, such as adding new controllers to Catalyst or new tables in DBIx::Class. For these types of activities you may find having a code generator speeds up some of the grunt work and promotes uniformity of design. App::Skeltor is such a code generator.

The core design is simple. You install App::Skeltor and any of the code patterns on CPAN that you wish to derive projects from (typically using the Skeltor::Template::* namespace, but you can use any namespace, and project patterns can be attached to any arbitirary CPAN module). You then can use the 'skeletor' commandline application to generate code into a target directory, using expansion variables to customize how the directories and files are created.

For example if you wish to build a new project called Local::MyApp which is based off the Skeletor::Template::Example project, you'd install that distribution (via cpanminus or whichever tool you prefer) and then type something like the following:

    skeletor --template Skeltor::Template::Example \
      --as Local::MyApp \
      --directory ~/new_projects \
      --author 'John Napiorkowski <>' \
      --year 2015

This would create a new project which consists of directories and files that have been generated and customized based on the commandline options given.

Alternatively you may use the URL hosted version of App::Skeletor which will always track the most current release. This allows you to use the tool without installing it first, making it useful for bootstrapping new development environments:

    curl -L | perl - \
      --template Skeletor::Template::Example \
      --as Local::MyApp \
      --author 'test author'

This assumes a working internet connection as well as some version of Perl installed and the curl commandline tool installed. In general this should be true for most Unix and Unixlike systems. However running an application directly off the internet this way may violate your companies security policies (and some so common sense) so use this option with caution.

NOTE directory and year are optional, and default to the current working directory and current year respectively. Some project templates may define additional configuration options, you should review the documentation.

NOTE Template distributions may define custom options for the commandline tool. You should review its documentation to make sure you are using it properly.

NOTE If you specify a template that is not currently installed, App::Skeletor will download it and install it to a temporary area for one time use. When the application exits, the temporary install is cleaned up.


As best as we can we try to replicat user/group/world read/write permissions defined in the template files to the project generated files.


You may store repeated or common configuration options in ~/skeletor.json, for example:

    cat ~/.skeletor.json 
      "--author": "John Nap"

Then when you build a project the '--author' option will be preloaded.


Other similar boilerplate code generators exist on CPAN. For example Catalyst::Devel has a commandline tool for creating a simple Catalyst project. Dancer2, Mojolicious also have dedicated project builders. App::Skeletor differs from those approaches in that it is detached from a particular project domain and thus can be more generically useful. This should give the community the chance for people to suggest their favorite approach to bootstrapping a project without forcing people to accept default options they don't like (current approach tends to be one size fits no one).

When comparing App::Skeletor to similar generic code builders like Dist::Zilla minting profiles, the main different is that App::Skeletor is dependency manager agnostic (doesn't require Dist::Zilla). I think its also a lot more simple than a minting profile.

App::Skeletor is probably more comparable with tools like Module::Starter which at this time are more mature tools. If App::Skeltor has tool many rough edges you may wish to take a look. At this point the main comparison is that I think the way a project skelton is created and organized is significantly easier to understand (famous last words I know :) ). Also App::Skeltor can be run directly from the URL hosted version, if you are not afraid of that!


The following configuration options are available, which are used as template variables and directory/file path expansions.


This is the namespace of the distribution containing the templates for generating a new project. For example, Skeletor::Template::Example.

If the distribution is not already installed into your @INC, we will download it and install it into a temporary directory. After generating files the temporary install is deleted. Obviously you need a working internet connection for this feature to work.



The new project Perl namespace, as you might use it in a 'package' declaration. For example "Local::MyApp". Use this to declare the base package for your new project.


Derived from "as". We substitute '::' for '-' to create a project 'name' that is normalized to the CPAN specification. For example 'Local-MyApp'



Same as "name" but using lowercased characters via 'lc'. For example 'local-myapp'.



Same as name but using lowercase characters via 'lc' and substituting all '-' characters with '_'. For example 'local_myapp'.


Given a "as" like "Local::My::App":

When used as an expansion for a directory expands to a nest of directories such as "Local/My/App". Directories will be created as needed.

When used as an expansion for a filename, expands directories as needed and creates a terminal file as needed such as "Local/My/App". Extensions are preserved, for example "${namespace_fullpath}.pm" becomes "Local/My/".

When used as a variable in a template, resolves to a Path::Tiny object that points to the directory+filename as already described.


Used in templates, set to the project author.


Year information for setting project copyright, etc. Default is current year.


An App::Skeletor template is just a CPAN module under any namespace you like (athough Skeletor::Template::* is not a terrible place to put one to make it easier for people to find) with a share/skel directory which should contain asset files (files copied to a new project without alteration), project templates (files that are copied to a new project but are first processed thru Template::Tiny to customize them) and directories. Directory names may also contain expansion variables in order to customize directory layout.

There is a reasonable complex example on CPAN under the namespace Skeletor::Template::Example which you may refer to as a somewhat complex template that includes all the mentioned types of data. You may find reviewing the example to be a faster way to understand how to make your own project templates.

Here is a very simple template with explanation to get you started. The example namespace given is mythical and does not exist on CPAN. In this example a path ending in '/' indicates a directory.


So first of all you should note that the template is just a normal CPAN module that declares its installation process and has a file (in this case under 'lib/Local/Skeletor/Template/') that should be used to describe what the skeleton does. Also note that you may include skeleton template files under any CPAN module you wish, it doesn't need to be stand alone.

The main work happens under 'share/skel/' which is the root directory that App::Skeletor uses when finding a template pattern. The way it works is that we traverse the filesystem recursively and copy directories and files from the project template share/skel/ to the target directory, performing any template expansions as needed. Template variable are defined above. We expand directories and files by matching a template variable in the path using a similar approach as we do variable interpolation in a string. for example a directory called "__name__" would expand to the project name variable (which is derived from the "as" commandline option.

In the case where you need to combine a template variable with other characters you may do so as in the example "".

Any file ending in '.ttt' is considered a template and is processed via Template::Tiny expanding variables as described in the previous section. We trucate the '.ttt' as part of the conversion process so a file template "" becomes '' in the build directory.


When you create you template distribution the bulk of you code will go under share/skel. However you may use distribution module (the file for example in lib/Skeletor/Template/ to customize aspects of the build process. The following methods may be defined in your distribution module.


This method is called in class context and should return an array of options as Getopt::Long::Descriptive describes for @opt_spec (the second of the three arguments one passes to 'describe_options'. You may use this to add custom template and file expansion variables to your template.


John Napiorkowski


Copyright 2015, John Napiorkowski

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.