Skip to content

Extensions API

Robert Grider edited this page Feb 22, 2016 · 40 revisions
Clone this wiki locally

For background information on extensions in NetLogo, see the Extensions section of the User Manual.

Several sample extensions are included with NetLogo. The full Java (or Scala) source code for all of them is hosted on GitHub. Most are in the public domain. Some are copyrighted, but under an open-source license.

Many extensions developed by users are available for download from the Extensions page. Most of them include source code.

To discuss NetLogo development, including usage of NetLogo APIs, browse or join the netlogo-devel group.

Writing Extensions

This page introduces this facility for Java programmers. We'll assume that you know the Java language and related tools and practices.

Our API's are also usable from other languages for the Java Virtual Machine, such as Scala. Following the Java information is a section on how to write an extension in Scala.


A NetLogo extension consists of a folder with the following contents:


  • A JAR file with the same name as the extension, the following contents:
    • one or more classes that implementat org.nlogo.api.Primitive
    • a main class that implements org.nlogo.api.ClassManager
    • a NetLogo extension manifest file, with the following four tags:
      • Manifest-Version, always 1.0
      • Extension-Name, the name of the extension.
      • Class-Manager, the fully-qualified name of a class implementing org.nlogo.api.ClassManager.
      • NetLogo-Extension-API-Version, the version of NetLogo Extension API for which this JAR is intended. If a user opens the extension with NetLogo that has a different Extension API version, a warning message is issued. To tell which version of the Extension API your NetLogo supports, choose the "About NetLogo" item in the "Help" menu and then click on the System tab. Or, you can launch NetLogo.jar with the --extension-api-version argument.


  • If you want the extension to work in applets, .jar.pack.gz versions of the main JAR and all supporting JARs, compressed with Pack200
  • One or more additional JAR files which the extension requires.
  • A lib directory with any required native libraries.
  • One or more NetLogo models demonstrating how the extension is used.
  • A src directory containing the source code for the model
  • Documentation.

To build your extension, you must include NetLogo.jar in your class path. In addition, the lib directory (also from the NetLogo distribution) must be in same location as NetLogo.jar; it contains additional libraries used by NetLogo.jar.


Let's write an extension that provides a single reporter called first-n-integers.

first-n-integers will take a single numeric input n and report a list of the integers 0 through n - 1. (Of course, you could easily do this just in NetLogo; it's only an example.)

1. Create extension folder

Since an extension is a folder with several items, we first need to create our folder. In this example, it is called example. We will be doing all of our work in that folder. We will also want to create a src sub-folder to hold our Java code, and a classes sub-folder for the compiled classes.

2. Write primitives

The primitives are implemented as one or more Java classes. The .java files for these classes should be put in the src sub-folder.

A command performs an action; a reporter reports a value. To create a new command or reporter, create a class that implements the interface org.nlogo.api.Command or org.nlogo.api.Reporter, which extend org.nlogo.api.Primitive. In most cases, you can extend the abstract class org.nlogo.api.DefaultReporter or org.nlogo.api.DefaultCommand.

DefaultReporter requires that we implement:

Object report (Argument args[], Context context)
  throws ExtensionException;

Since our reporter takes an argument, we also implement:

Syntax getSyntax();

Here's the implementation of our reporter, in a file called src/

import org.nlogo.api.*;

public class IntegerList extends DefaultReporter {
  // take one number as input, report a list
  public Syntax getSyntax() {
    return Syntax.reporterSyntax(
    new int[] {Syntax.NumberType()}, Syntax.ListType());
  public Object report(Argument args[], Context context)
      throws ExtensionException {
    // create a NetLogo list for the result
    LogoListBuilder list = new LogoListBuilder();
    int n ;
    // use typesafe helper method from 
    // org.nlogo.api.Argument to access argument
    try {
      n = args[0].getIntValue();  
    catch(LogoException e) {
      throw new ExtensionException( e.getMessage() ) ;
    if (n < 0) {
    // signals a NetLogo runtime error to the modeler
    throw new ExtensionException
      ("input must be positive");
    // populate the list. note that we use Double objects; NetLogo
    // numbers are always Doubles
    for (int i = 0; i < n; i++) {
    return list.toLogoList();


  • The number objects we put in the list are Doubles, not Integers. All numbers used as NetLogo values must be of type Double, even if they happen to have no fractional part.
  • To access arguments, use org.nlogo.api.Argument's typesafe helper methods, such as getDoubleValue().
  • Throw org.nlogo.api.ExtensionException to signal a NetLogo runtime error to the modeler.

A Command is just like a Reporter, except that reporters implement Object report(...) while commands implement void perform(...).

2. Write a ClassManager

Each extension must include, in addition to any number of command and reporter classes, a class that implements the interface org.nlogo.api.ClassManager. The ClassManager tells NetLogo which primitives are part of this extension. In simple cases, extend the abstract class org.nlogo.api.DefaultClassManager, which provides empty implementations of the methods from ClassManager that you aren't likely to need.

Here's the class manager for our example extension, src/

import org.nlogo.api.*;

public class SampleExtension extends DefaultClassManager {
  public void load(PrimitiveManager primitiveManager) {
      "first-n-integers", new IntegerList());

addPrimitive() tells NetLogo that our reporter exists and what its name is.

3. Write a Manifest

The extension must also include a manifest. The manifest is a text file which tells NetLogo the name of the extension and the location of the ClassManager.

The manifest must contain three tags:

  • Extension-Name, the name of the extension.
  • Class-Manager, the fully-qualified name of a class implementing org.nlogo.api.ClassManager.
  • NetLogo-Extension-API-Version, the version of NetLogo Extension API for which this JAR is intended. If a user opens the extension with NetLogo that has a different Extension API version, a warning message is issued. To tell which version of the Extension API your NetLogo supports, choose the "About NetLogo" item in the "Help" menu. Or, you can launch the NetLogo.jar with the --extension-api-version argument.

Note that the API version is rarely the same as the NetLogo version. For example, all of the releases in the NetLogo 5.x series have the same API version, namely 5.0.

Here's a manifest for our example extension, manifest.txt:

Manifest-Version: 1.0
Extension-Name: example
Class-Manager: SampleExtension
NetLogo-Extension-API-Version: 5.0

The NetLogo-Extension-API-Version line should match the actual version of NetLogo Extension API you are using.

Make sure even the last line ends with a newline character.

4. Create a JAR

To create an extension's JAR file, first compile your classes as usual, either from the command line or using an IDE.

Important: You must add NetLogo.jar (from the NetLogo distribution) to your classpath when compiling, and the lib directory must be accessible in the same location as NetLogo.jar.

Important: If you're not careful, your extension won't work on Java 6, which means it won't work for most NetLogo users. See the “Supporting old Java versions” section below.

Each of our sample extensions on GitHub includes a command-line build, invoked with the sbt package or make command.

Here's an example of how compiling your extension might look from the command line if you aren't using sbt or make:

$ mkdir -p classes     # create the classes subfolder if it does not exist
$ javac -classpath NetLogo.jar -d classes src/ src/

You will need to change the classpath argument to point to the NetLogo.jar file from your NetLogo installation. For example, on Mac OS X you'd do:

javac -classpath "/Applications/NetLogo 5.0/NetLogo.jar" -d classes src/ src/

This command line will compile the .java and put the .class files in the classes subfolder.

Then create a JAR containing the resulting class files and the manifest. For example:

$ jar cvfm example.jar manifest.txt -C classes .

For information about manifest files, JAR files and Java tools, see

5. Use your extension in a model

To use our example extension, put the example folder in the NetLogo extensions folder, or in the same directory as the model that will use the extension. At the top of the Code tab write:

extensions [example]

Now you can use example:first-n-integers just like it was a built-in NetLogo reporter. For example, select the Interface tab and type in the Command Center:

observer> show example:first-n-integers 5
observer: [0 1 2 3 4]

Scala Tutorial

Now let's rewrite the extension in Scala.

If you are using Scala, you'll need to make sure you are using Scala 2.9. (2.9.1, 2.9.2, and 2.9.3 are all acceptable.) Other versions such as 2.10 or 2.11 will not work.

1. Create extension folder

Let's start with a new folder called, example-scala. As with the Java example, create src and classes sub-folders.

2. Write primitives and a Class Manager

We'll put all of the source code in one file. Here's the implementation of our reporter, and our ClassManager, in a file called src/IntegerList.scala:

import org.nlogo.api._
import org.nlogo.api.Syntax._
import org.nlogo.api.ScalaConversions._

class SampleScalaExtension extends DefaultClassManager {
  def load(manager: PrimitiveManager) {
    manager.addPrimitive("first-n-integers", new IntegerList)

class IntegerList extends DefaultReporter {
  override def getSyntax = reporterSyntax(Array(NumberType), ListType)
  def report(args: Array[Argument], context: Context): AnyRef = {
    val n = try args(0).getIntValue
    catch {
      case e: LogoException =>
    throw new ExtensionException(e.getMessage)
    if (n < 0)
      throw new ExtensionException("input must be positive")
    (0 until n).toLogoList

Mostly this is a straightforward, line-by-line translation of the Java version.

One difference is worth noting. In the Java version, we explicitly converted ints to Double objects. As previously mentioned, all numbers used as NetLogo values must be of type Double, even if they happen to have no fractional part. In the Scala version we leverage implicit conversions to do this work for us. We do so by importing org.nlogo.api.ScalaConversions._, which provides us with two new methods via implicit conversions. The first is toLogoList, which converts Scala Seqs to LogoLists as seen in: (0 until n).toLogoList. The second is toLogoObject, which converts any supported Scala value to the appropriate NetLogo type. The conversions provided by toLogoObject are:

  • from scala.Boolean, java.lang.Boolean to java.lang.Boolean
  • from scala.Char, java.lang.Character to String
  • from scala.Byte, java.lang.Byte to java.lang.Double
  • from scala.Short, java.lang.Short to java.lang.Double
  • from scala.Int, java.lang.Integer to java.lang.Double
  • from scala.Float, java.lang.Float to java.lang.Double
  • from scala.Long, java.lang.Long to java.lang.Double
  • from scala.Double to java.lang.Double
  • from scala.Seq to org.nlogo.api.LogoList
  • any already valid recognized type (e.g. String, ExtensionObject) passes through unaltered
  • anything else results in an error

The conversions to LogoList are recursive. Nested collections in the input will be converted to nested LogoLists in which all elements have been converted by toLogoObject. ExtensionObjects, on the other hand, are not recursed into.

Using the toLogoObject conversion is simple. Just call the method on an an Any. Example: 7.toLogoObject

3. Create a JAR

To create an extension's JAR file, first compile your classes as usual, either from the command line or using an IDE.

Important: As when compiling Java, you must add NetLogo.jar (from the NetLogo distribution) to your classpath when compiling.

Here's an example of how compiling your extension might look from the command line:

$ mkdir -p classes     # create the classes subfolder if it does not exist
$ scalac -classpath NetLogo.jar -d classes src/

You will need to change the classpath argument to point to the NetLogo.jar file from your NetLogo installation. This command line will compile the .java and put the .class files in the classes subfolder.

Then create a JAR containing the resulting class files and the manifest exactly as was done with the Java classes. For example:

$ jar cvfm example-scala.jar manifest.txt -C classes .

4. Use your extension in a model

Using a Scala extension is the same as using a Java extension. However there is one caveat: NetLogo ships with a stripped down version of scala-library.jar. While most common classes (Array, List, Map) are present, it may be best to check, especially if your extension makes use of less common classes.

To check which classes are present in the scala-library.jar that ships with NetLogo, in the lib directory inside the NetLogo directory type this at the command line:

$ jar tf scala-library.jar

If you find that a class used by your extension is missing (either by checking manually or via a ClassNotFound exception), there is still hope. Place a copy of a full version of scala-library.jar into the root of your extensions directory (in this case example-scala). Or, since the full scala-library.jar is large (over 4 megabytes), you may wish to prepare a smaller jar containing only the specific missing classes you need to supply.

Extension development tips


Your class manager is instantiated in a fresh JVM classloader at the time a model using the extension is loaded.

This is done so that extensions are unloadable, so that when you open a new model, the extensions used by the previous model can be unloaded and the memory they used reclaimed. (The JVM does not allow unloading particular classes; you can only unload an entire classloader at once.)


Don't forget to include NetLogo.jar in your class path when compiling. This is the most common mistake made by new extension authors. (If the compiler can't find NetLogo.jar, you'll get error messages about classes in the org.nlogo.api package not being found. If the lib directory isn't in the same location as NetLogo.jar, you'll get errors about other classes not being found.)

If you use sbt or maven, adding the NetLogo jar can be done through your build tool. In sbt, add the following to your build.sbt

libraryDependencies += "org.nlogo" % "NetLogo" % "5.2.0" from ""

For maven, download the jar from and add the following to your pom.xml.


Supporting old Java versions

NetLogo is compiled targeting Java 6, but runs in a Oracle Java 8 VM. This means that your extension should be usable as long as it targets Java 6, 7, or 8. Be aware that if you are compiling with Apple Java 6 on a Mac, the Java distribution contains classes and methods which will not be available to NetLogo at runtime. Extension authors are encouraged to begin target Java 8 in future releases.

If you would like to continue building against Java 6 for the time being, you can:

  • Specify the desired version with -source 1.6 -target 1.6 options to javac (or equivalent in your IDE) to tell the newer compiler to emit class files that are compatible with the older Java versions. This ensures that your code doesn't use any Java 7-or-later-only Java language features.
  • Use the -bootclasspath option to javac (or IDE equivalent) to compile against the Java 6 class libraries. (Note that this requires installing Java 6 anyway.) This ensures that your code doesn't make any Java-7-or-later-only Java API calls.
  • Review the Oracle documentation on incompatibilities between JVM 6 and 7 and JVM 7 and 8. While these lists of incompatibilities are quite short, they could cause unexpected problems if your code is affected.

Debugging extensions

There are special NetLogo primitives to help you as you develop and debug your extension. These are considered experimental and may be changed at a later date. (That's why they have underscores in their name.)

  • print __dump-extensions prints information about loaded extensions
  • print __dump-extension-prims prints information about loaded extension primitives
  • __reload-extensions forces NetLogo to reload all extensions the next time you compile your model. Without this command, changes in your extension JAR will not take effect until you open a model or restart NetLogo.

Language Tests

You can run language test from within your extension's sbt session. The NW-Extension uses this. See its build.sbt for an example.


Similarly, you can run benchmarks from within your extension's sbt session. If you setup language tests for the extension, then just put your benchmark models in the models/test/benchmarks subfolder of your extension's root folder. Then you can run them with:

test:run-main org.nlogo.headless.HeadlessBenchmarker BenchmarkName

Third party JARs

If your extension depends on code stored in a separate JAR, copy the extra JARs into the extension's directory. Whenever an extension is imported, NetLogo makes all the JARs in its folder available to the extension.

If you plan to distribute your extension to other NetLogo users, make sure to provide installation instructions.

Applet support

We no longer recommend using applets.

But if you want your extension to work in applets, compile it using NetLogoLite.jar instead of NetLogo.jar, to be sure you are only referencing classes and methods that are available in the applet jar.

To keep the size of NetLogoLite.jar down, we use ProGuard to aggressively strip out unreferenced classes and methods. If ProGuard is removing something that your extension needs, let us know.

You'll need to run your extension's main JAR, and any supporting JARs too, through Pack200 to produce compressed .jar.pack.gz versions that are much smaller and therefore load much faster than plain JARs. In theory including the packed jars should be optional, but we've found that in practice, without them applets won't work on some web servers. Here's an example command line for running the pack200 tool:

pack200 --modification-time=latest --effort=9 --strip-debug \
  --no-keep-file-order --unknown-attribute=strip \
  sample.jar.pack.gz sample.jar

If you have any required supporting JARs, you'll need to override the additionalJars method on ExtensionManager to return a list of their names. (see e.g.

If you are with comfortable with building NetLogo yourself, you can also experiment with adding stuff to the project/proguard/lite.txt file to change what is included in NetLogoLite.jar (see the ProGuard documentation). We are trying to keep the size of that JAR as small as possible, but open to the idea of adding stuff that really should be there.

For debugging applets, the Java Console can be very useful: it will allow you to see exceptions that are raised by your code (java.lang.NoSuchMethodError exceptions are usually a sign of trying to use something that was stripped away by ProGuard).

Extensions written in Scala

If your extension is written in Scala, you may not be able to compile against the applet JAR, because we use ProGuard to strip ScalaSig attributes from that JAR, to save space. What this typically causes to fail is implicit conversions, such as the ones in ScalaConversions and LogoList, since the fact that a method is implicit is stored in the ScalaSig attribute. If you hit this problem, either compile against the regular JAR instead, or explicitly call the implicit methods by name.

Even if you extension does compile, it might still fail at runtime. One reason for that is because ProGuard also strips away parts of the Scala library that NetLogo does not use, but when you compile your extension, you compile it against the full Scala library, so you get no compile-time errors.

And it is not always obvious: some things involving reflection do not work. Structural types use reflection under the hood and are amongst the things that do not work. A pattern like this involves structural types:

val y = new X { def someNewMethod = () }

This one can usually be replaced by something like:

object y extends X { def someNewMethod = () }

You might also find other patterns like this. Again, if that is the case, let us know.

Documenting your extension

Note that there is no way for the modeler to get a list of commands and reporters provided by an extension, so it's important that you provide adequate documentation.


Don't forget to consult the NetLogo API Specification for full details on these classes, interfaces, and methods.

You may also find it useful to consult the NetLogo source code on GitHub.

The extensions facility is not yet complete. The API doesn't include everything you might expect to be present. Some facilities exist but are not yet documented. If you don't see a capability you want, please let us know. Do not hesitate to contact us with questions, as we may be able to find a workaround or provide additional guidance where our documentation is thin.

Hearing from users of this API will also allow us to appropriately focus our efforts for future releases. We are committed to making NetLogo flexible and extensible, and we very much welcome your feedback.

Building Pre-Made Extensions with sbt on Windows

At times you may want to download extension code from GitHub and build it yourself (possibly for the purpose of making modifications). The following method will work for extensions built with "sbt package". For example: Possibly

First, navigate to the extension that you want to download on GitHub. Download the repository as a ZIP file and unzip it. If you wish to modify the code, open the /src directory and modify the text files inside using your text editor or IDE of choice.

Before building the extension, you require certain software packages. Firstly, you need sbt, or the Simple Build Tool, which will allow you to build the extension. Download and run the MSI under the "Windows" section at

Now you must add the sbt folder to your system path. This is so that when you tell the computer to run the program called "sbt," it knows where to find the program you're looking for. The sbt directory will probably be something like C:\Program Files (x86)\sbt. You can look up instructions for modifying your system path online. One way to do it is to navigate to System under the Control Panel, select "Advanced System Settings" on the left, select "Environmental Variables" in the "Advanced" tab, select "PATH" under "System Variables", and select "Edit." Then, add a semicolon at the end of the long text, and copy-paste the directory (C:\Program Files (x86)\sbt or similar).

While you're in \sbt, you may want to run sbt.jar and sbt.bat. This step may or may not do anything.

You also need javac.exe to compile the package. You can download the Java Development Kit, which contains this program, at If you have issues, version 1.6.0-31, at, may be more successful. Once you download the JDK, add the directory which contains javac.exe to your system path as before: it should be something like C:\Program Files (x86)\Java\jdk1.7.0_03\bin. Check that the directory contains javac.exe.

Finally, download Git from, and add the directory containing git.exe (C:\Program Files (x86)\Git\bin or similar) to your system path.

You are now prepared to build the extension. Open the Command Prompt (search for "cmd" in the Start Menu). Enter the command "cd [directory]" to navigate to the extension (for example, "cd C:\GoGo Extension"). Then enter "sbt package." Your code should compile at this time. If there are errors in your code, the command prompt will output error messages.

You should end up with a .jar file in the extension directory. Copy this .jar file to the appropriate directory in NetLogo (e.g. C:\Program Files (x86)\NetLogo 5.0.5\extensions\gogo). The next time you run NetLogo, you should have the new version of the extension.

Something went wrong with that request. Please try again.