Go to page content

Module structure

An overview of a module’s files and directories.

A module is a single directory.  It contains an Erlang module implementing a gen_server and subdirectories for templates, actions, scomps, dispatch rules and more.

The generic structure is:


Changes to the Erlang files in a module are visible after a make and reload. Any new lib or template files, or changes in the dispatch rules are visible after the module indexer has rescanned all modules. You can do this with the “rescan modules” button on the modules page in the admin. Changes to templates are directly visible.

The module server, mod_example.erl

The code of the smallest possible module is below.  The name of this module must be the same as the name of the module’s directory.

-author("Nomen Nescio <nomen@example.com>").
-mod_title("Your module title").
-mod_description("Description what this module does.").

The mod_title and mod_description properties will be visible on the admin modules page. The priority defines the how important the module is. The highest priority is 1, the default is 500. Modules with higher priority are checked first for templates, actions, scomps etc. Modules with the same priority are sorted by ascending module name.

You can export an optional init/1 function. This function will be called when the module is started. The parameter is a context record initialized for the site the module will be running in. This is useful when you need to initialize the database or other data structures for which you don’t need a running process.

When you need a running process then you must implement your module as a gen_server.

A minimal gen_server based module

A module can also be implemented as a gen_server. In that case you will need to add the behaviour and gen_server functions. You also need to change the init/1 function to accept an property list, which contains the site definition and a {context,Context} property.

This server module will be started for every site in a Zotonic system where the module is enabled, so it can’t be a named server.

-author("Nomen Nescio <nomen@example.com>").

-mod_title("Your module title").
-mod_description("Description what this module does.").

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {context}).

start_link(Args) when is_list(Args) ->
    gen_server:start_link(?MODULE, Args, []).

init(Args) ->
    process_flag(trap_exit, true),
    {context, Context} = proplists:lookup(context, Args),
    {ok, #state{context=z_context:new(Context)}}.

handle_call(Message, _From, State) ->
    {stop, {unknown_call, Message}, State}.

handle_cast(Message, State) ->
    {stop, {unknown_cast, Message}, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.


In this directory you can add actions. Every action name must be prefixed with the word “action” and the module name. For example the filename for the action “dialog_open” in the module “mod_base” will be: action_base_dialog_open.erl


This directory contains files with dispatch rules.  You can name your files like you want, though don't give them the extension “.erl” because then the Makefile will try to compile them.


The lib (short for library) directory contains static images, css and javascript files. They will be served with via the lib dispatch rule. The usual layout of the lib directory is:


See also the {% lib %} template tag for accessing css and javascript files.


Scomps are prefixed in the same way as actions, except that the word “scomp” is used. For example the scomp “button” in the module “mod_base” has as file name: “scomp_base_button.erl”


This directory contains resources used by the dispatch rules. Resources must have unique names, as they are compiled and loaded in the Erlang system. Best is to prefix every resource with “resource” and the name of the module, for example “resource_admin_edit.erl”.


This directory contains model files.  The module name of a model always starts with “m_”, for example “m_comment” which could be used in the templates as ”m.comment”.  Be careful to give your models an unique name to prevent name clashes with other models and Erlang modules.


This directory contains all templates. Templates don't have any prefix in their name, as they are not (directly) compiled as erlang modules. In Zotonic there are some simple naming rules for templates:

  • All templates must have the extension “.tpl”
  • Templates used as a complete page can have any name: ”my_special_page.tpl”
  • Templates used as the base of other templates, using the {% extend %} tag, have the word “base” in them: ”base.tpl”
  • Templates only used by including them in other templates start their name with an underscore: “_example.tpl“
  • The home page uses the template “home.tpl”


Template filters are used to modify values.  For example:

{{ value|filter }}

Template filters must have an unique name, reflecting the filter’s name.  For example, the filter “tail” resides in the module “filter_tail” and has the function name “tail”.  Filters are added in the filters directory.  The template compiler will insert references to the correct modules into the compiled templates.  A missing filter will result in a crash of the compiled template.


Validators are prefixed in the same way as actions and scomps, except that the word “validator” is used. For example the validator “email” in the module “mod_base” has as file name: “validator_base_email.erl”


The services folder holds API methods that you can use to access Zotonic from another application.

Services are named a bit differently: the name of the module is always used  in the service name: The service "base/export" will be found in the file "mod_base/services/service_base_export.erl". This particular service can be found at "http://yoursite.com/api/base/export".

This page is part of the Zotonic documentation, which is licensed under the Apache License 2.0.