How to Check If a Perl Module Is Installed (and Loadable)
Question
how to check if a perl module is installed
How to Check If a Perl Module Is Installed (and Loadable)
Difficulty: Beginner (with some Intermediate best practices)
Tags: perl, cpan, modules, dependency-management, @INC, PERL5LIB, local::lib, require, use
In Perl, “is a module installed?” is really two closely related questions:
- Is the module’s file present somewhere on disk? (e.g.,
Some/Module.pmexists) - Can this particular Perl interpreter load it right now? (i.e., will
require/usesucceed with the current@INC, environment variables, and permissions?)
For production and automation, you almost always care about #2: whether the module is loadable by the same Perl binary and environment your app uses. A module might exist on disk but not be loadable if you’re running a different Perl, a different @INC, or missing compiled dependencies.
Key Concept: @INC (where Perl looks for modules)
When you do use Foo::Bar; or require Foo::Bar;, Perl searches for Foo/Bar.pm through the list of directories in @INC. That list is influenced by:
- The Perl installation (system Perl vs perlbrew/plenv/asdf, etc.)
PERL5LIB(adds library paths)use libstatements in your codelocal::lib(common for per-user installs)- Container/runtime filesystem layout
This is why two commands can disagree:
- Your shell might run
/usr/bin/perl - Your app (or cron job) might run
/opt/perl/bin/perl
Always check with the same Perl binary your program uses.
Fast Command-Line Checks (common in ops and debugging)
These are not “Perl code examples” (the runnable examples come later), but they’re very practical:
-
Try to load it:
perl -MSome::Module -e1If the module is loadable, it exits successfully (exit code 0) and prints nothing. If it’s not loadable, you’ll see an error like “Can’t locate Some/Module.pm in @INC …”.
-
Find the module file Perl would use:
perldoc -l Some::ModuleIf installed, prints the path to the module’s file. If not installed, you’ll get a “No documentation found” message or a non-zero exit status (depends on platform and configuration).
-
Ask CPAN clients (if present):
cpan -D Some::Module cpanm --info Some::ModuleUseful, but remember: CPAN tooling can be configured per-user and may not reflect what the runtime interpreter sees unless you’re careful about which Perl and environment it uses.
Best Practice Approach in Perl Code
Inside Perl code, the safest, most common pattern is:
- Convert a module name to a file path (
Foo::Bar→Foo/Bar.pm) - Attempt to
requireit inside anevalblock - Optionally call
->importif you need exported symbols (to mimicuse) - Inspect
$@if loading fails
This is preferred over eval "use $module" when the module name can vary, because string eval has code-injection risks if the input is not trusted.
Runnable Perl Code Examples (with Expected Output)
Example 1: Basic “installed/loadable?” check using require
This example checks one core module (File::Spec, which should be present in any normal Perl distribution) and one fake module that is guaranteed to be missing.
#!/usr/bin/env perl
use strict;
use warnings;
sub module_to_file {
my ($module) = @_;
(my $file = $module) =~ s{::}{/}g;
return "$file.pm";
}
sub is_module_loadable {
my ($module) = @_;
my $file = module_to_file($module);
return eval { require $file; 1 } ? 1 : 0;
}
for my $module ("File::Spec", "Some::Made::Up") {
print "$module: ", (is_module_loadable($module) ? "installed" : "NOT installed"), "\n";
}
Expected output:
File::Spec: installed
Some::Made::Up: NOT installed
Why this works: require searches @INC for the module file. Wrapping it in eval prevents the program from dying; instead, failures populate $@.
Example 2: Optional dependency with a safe fallback
Real applications often have optional features (faster JSON, optional DB drivers, optional telemetry). The best pattern is: try the preferred module; if it fails, fall back to a known-good alternative.
#!/usr/bin/env perl
use strict;
use warnings;
sub module_to_file {
my ($module) = @_;
(my $file = $module) =~ s{::}{/}g;
return "$file.pm";
}
sub load_module {
my ($module) = @_;
my $file = module_to_file($module);
return eval { require $file; 1 } ? 1 : 0;
}
my $preferred = "Some::Made::Up"; # pretend this is a faster backend
my $fallback = "JSON::PP"; # core on many perls
my $json_class;
if (load_module($preferred)) {
$json_class = $preferred;
} else {
die "Neither $preferred nor $fallback could be loaded\n" unless load_module($fallback);
$json_class = $fallback;
}
my $json = $json_class->new->canonical(1);
my $encoded = $json->encode({ hello => "world" });
print "Using JSON engine: $json_class\n";
print "JSON: $encoded\n";
Expected output:
Using JSON engine: JSON::PP
JSON: {"hello":"world"}
Notes: This pattern keeps your app resilient: it runs with the fallback, but you can still deploy the preferred module in environments where you want better performance.
Example 3: Report why a module is missing (clean, stable error messaging)
When you’re building diagnostics (health checks, startup self-tests, CLI doctor commands), it’s useful to show why loading failed without dumping environment-specific @INC noise.
#!/usr/bin/env perl
use strict;
use warnings;
sub module_to_file {
my ($module) = @_;
(my $file = $module) =~ s{::}{/}g;
return "$file.pm";
}
sub try_load {
my ($module) = @_;
my $file = module_to_file($module);
my $ok = eval { require $file; 1 };
return (1, "") if $ok;
my ($first_line) = split /\n/, ($@ // "");
$first_line =~ s/ at .*//; # remove file/line suffix for stable output
return (0, $first_line || "Unknown error");
}
for my $module ("strict", "Some::Made::Up") {
my ($ok, $err) = try_load($module);
if ($ok) {
print "$module: ok\n";
} else {
print "$module: missing ($err)\n";
}
}
Expected output:
strict: ok
Some::Made::Up: missing (Can't locate Some/Made/Up.pm in @INC (you may need to install the Some::Made::Up module))
Checking a Module Version (when you need a minimum)
Sometimes “installed” isn’t enough; you need “installed at least version X”. Perl supports this directly:
use Some::Module 1.23;(compile-time)Some::Module->VERSION(1.23);(runtime; dies if too old)
Important behavior:
usehappens at compile time; if it fails, your program won’t start (good for hard requirements).requirehappens at runtime; you can decide what to do if it fails (good for optional features).- Some modules don’t define
$VERSIONclearly; version checks can be awkward for those (rare for CPAN modules, more common for tiny internal packages).
Best Practices (Production-Ready Guidance)
- Check using the same Perl binary your app uses. On systems with multiple Perls,
perl -vandwhich perlmatter. - Fail fast for required dependencies. Use plain
use Module;for required modules so startup fails loudly and early. - Use runtime loading only for optional dependencies. Prefer
eval { require ... }and then feature-gate functionality. - Avoid string
evalfor dynamic module names. If the module name comes from user input or config, string eval can be a code-injection vector. Convert to a filename andrequirethat. - Remember that “installed” can differ by environment. Cron, systemd services, and web servers may not inherit your shell’s
PERL5LIBorlocal::libsetup. - Prefer declaring dependencies instead of probing for them. For CPAN distributions, use
cpanfile,Makefile.PL, orBuild.PLso installation tools handle it up front.
Common Pitfalls
- Using the wrong Perl. “It works in my terminal” but fails in production often means different interpreters or different
@INC. - Confusing “file exists” with “module loads.” A module might exist but fail to load due to missing shared libraries (XS modules), missing transitive dependencies, or syntax incompatible with your Perl version.
- Forgetting that
usealso imports symbols.require Module;loads code but does not automatically callModule->import. If you relied on exported functions, you must callModule->import(...)yourself. - Reading too much into
%INC.%INCrecords what’s been loaded in the current process. It doesn’t tell you what’s installed system-wide; it tells you what has already been required. - Assuming
perldocalways works. Minimal containers sometimes omit perl-doc packages, soperldoc -lmay not be available even if the module is.
Real-World Usage Patterns
- Startup dependency check: At process start, load required modules normally; for optional ones, test and log capability flags (e.g., “TLS enabled”, “fast JSON enabled”).
- Plugin discovery: Read a list of plugin module names from config,
requireeach, and keep only those that load successfully. - Health checks and diagnostics: Build a “doctor” command that attempts to load critical modules and prints actionable errors (missing module, wrong version, missing shared library).
- Deployment verification: In CI/CD or container builds, run a script that loads every required module with
perl -M...to ensure the image truly contains everything.
Summary
The most reliable way to check if a Perl module is installed is to try to load it with the same Perl interpreter and environment your application uses. In scripts, prefer eval { require ... } for optional modules and plain use for required dependencies. When you need minimum versions, use Perl’s built-in version checking. Always account for @INC and multi-Perl environments to avoid confusing false negatives.
Verified Code
Executed in a sandbox to capture real output. • 14ms
File::Spec: installed
Some::Made::Up: NOT installed
(empty)Was this helpful?
Related Questions
- How to Write to a File in Perl (open/print, modes, safety, and best practices)
- How to Load a Module in Perl (use, require, @INC, and Best Practices)
- How to Run Perl Code on macOS (Terminal, Scripts, Shebangs, Modules, and Common Pitfalls)
- How to Add Elements to an Array in Perl (push, unshift, splice, indexing, and arrayrefs)
- How to Install Perl Modules on Windows (CPAN, cpanm, Strawberry Perl, ActiveState, local::lib)
- How to Compare Strings in Perl (eq/ne, lt/gt, cmp, case-insensitive, Unicode)