There isn't much to change between the implementation of a Perl CGI script such as the example above and the equivalent Apache/mod_perl handler.

The great advantage of using mod_perl is that it allows you to keep a Template object persistent in memory. The main benefit of this is that Perl can parse and compile all the Template Toolkit code and all your application code once when the server starts, rather than repeating it for each request. The other important benefit is that the Template object will cache previously used templates in a compiled state, from which they can be redeployed extremely quickly. A call to process a template becomes as efficient as a call to a precompiled Perl subroutine (which is indeed how it is implemented under the hood), bringing you runtime machine efficiency as well as the development-time human efficiency and convenience of using a template-driven presentation system.

Example D-5 shows a typical mod_perl handler roughly equivalent to the earlier Perl script.

Example D-5. Apache/

package Apache::MyTemplate;

use strict;
use Apache::Constants qw( :common );
use Template;
use vars qw( $TT );

sub handler {
  my $r = shift;

  # create or reuse existing Template object
  $TT ||= Template->new({
      INCLUDE_PATH  => '/usr/local/tt2/templates',

  my $data = {
      uri => $r->uri,
      copyright => '© 2002 Andy Wardley',
      weblinks  => [
            url   => '',
            title => 'Apache/mod_perl',
            url   => '',
            title => 'Template Toolkit',
      # ...and so on...


  $TT->process('example.html', $data, $r) || do {
      $r->log_reason($TT->error( ));
      return SERVER_ERROR;

  return OK;

You need to adjust the value of INCLUDE_PATH to point to the directory where header, example.html, and footer were created.

Here's the configuration section for the httpd.conf file:

PerlModule Apache::MyTemplate
<Location /example2>
  SetHandler perl-script
  PerlHandler Apache::MyTemplate

Of course, it's not particularly useful to have the template name hardcoded as it is here, but it illustrates the principle. You can implement whatever kind of strategy you like for mapping requests onto templates, using the filename, path information, or pretty much anything else that takes your fancy. No doubt you can already spot numerous other enhancements that you might make to your own handlers.

Figure D-1 shows what you should expect when issuing a request to /example2.

Figure D-1

Figure D-1. A sample response