Getting started

This guide helps you get started running and interacting with a local development server and tests. If you are a Full Time SWE onboarding, first check out the links/tutorials/account-settup detailed in New Full Time SWE Onboarding Material.

Setting up your environment

Start here! This step is a prerequisite for everything that follows, even if you only want to interact with a local server without pushing changes. If you're working in Windows, check out Getting started with Windows.
  1. 2.
    Install git on your machine.
  2. 3.
    Configure an SSH key with your GitHub account. We recommend not including the "UseKeychain yes" line or setting a password.
  3. 4.
    Install Docker
    • On Mac
      • Download Docker Desktop.
      • Run Docker Desktop and go to Preferences > Resources to increase max RAM for containers to at least 4GB (ideally 6GB), otherwise sbt compiles can get killed before completing and produce strange runtime behavior.
    • On Linux
      • Install Docker Engine for your Linux distribution.
      • Configure Docker to run in Rootless Mode. This will create generated files as the correct user, otherwise file permission issues occur.
      • Install Docker compose v2 by following these instructions.
  4. 5.
    Clone the CiviForm repo. This will create a copy of the codebase on your machine:
    1. 1.
      Open a terminal and navigate to the directory you'd like the copy of the CiviForm codebase to live.
    2. 2.
      In that directory, run the following (and/or refer to this guide):
      git clone [email protected]:civiform/civiform.git

A note on IDEs

Running SBT

You may use whichever IDE you prefer, though DO NOT use the IDE's built-in sbt (Scala Build Tool) shell if it has one. Instead, run bin/sbt to bring up an sbt shell inside the Docker container. The sbt shell allows you to compile, run tests, and run any other sbt commands you may need

Configuring IntelliJ

The easiest way to get IntelliJ to index the project correctly is to install the Scala plugin and open the project by specifying the build.sbt file in IntelliJ's open existing project dialog. If this isn't done correctly IntelliJ probably won't load library code correctly and will complain that it can't find symbols imported from libraries.
This setup will only include the files under (.../server), therefore, if you would like to edit other files under .../civiform, you need to add additional modules manually:
  • Go to File/Project Structure,
  • Select modules
  • Ensure civiform-server and sources are selected in second and third column,
  • Click on + on the right handside to add all folders under civiform except "server" to the content roots
If you still have trouble getting some symbols to show (such as routes packages), try the following, in order:
  1. 1.
    Go to Project Structure and add target/scala-2.13 to your Sources in the civiform-server Module.
  2. 2.
    Go to the sbt shell within IntelliJ and run compile.
  3. 3.
    Go to Preferences, then "Languages and Frameworks", then "Scala". Switch Error Highlighting from "Built-in" to "Compiler".

Configuring VSCode

  1. 1.
    Install the following extensions:
  2. 2.
    Run bin/vscode-setup to generate a pom.xml file that allows VSCode to resolve dependencies
  3. 3.
    Open the workspace file civiform.code-workspace in VSCode
  4. 4.
    Metals automatically detects the project. Click Import Build at the prompt.
    Screen Shot 2022-05-06 at 9 28 17 AM
  5. 5.
    Choose sbt at the prompt for multiple build definitions.
    Screen Shot 2022-05-06 at 9 51 24 AM
  • If source code isn't being indexed / symbols aren't found, you may need to clean the Java workspace. Trigger the command pallet and select Java: Clean Java Language Server Workspace
  • If a new dependency is added, the pom.xml file may be out of date. You'll need to either add the dependancies manually, or re-run the bin/vscode-setup script to regenerate the file.
Important files
VSCode uses the following files
  • server/pom.xml (maven dependancies for symbols)
  • server/.settings/*. (generated by sbt eclipse)
  • civiform.code-workspace (opens the top level directory, and server)

Running a local server

Note: the project makes heavy use of shell scripts for development tasks. Run bin/help to see a list of them.
  1. 1.
    To run the application, navigate to the civiform directory you created when you cloned the repo and run the following:
    To run the application using Azure instead of AWS, run:
    bin/run-dev –-azure
This will start up a dev instance of the application that uses Azurite, the Azure emulator, instead of local stack, the AWS emulator. This script sets an environment variable, STORAGE_SERVICE_NAME telling the application to run using the Azure emulator instead of AWS.
Tip: Once you have the local server working, you may want to set USE_LOCAL_CIVIFORM=1 by default in your environment. This will speed up reruns by not always redownloading the latest docker images (1-2GB each) which is not usually necessary.
Warning: There's a known issue where you may encounter a compile loop, the most reliable way to address that is to do bin/sbt clean before the above.
  1. 2.
    Once you see "Server started" in your terminal (it will take some time for the server to start up), you can access the app in a browser at http://localhost:9000. Be patient on the initial page load since it will take some time for all the sources to compile.
If you want to use the Log In flow see those instructions which include a one-time setup too.
The bin/run-dev script uses docker-compose (see docker-compose.yaml). It enables Java and Javascript hot-reloading: when you modify most files, the server will recompile and restart. This is pretty time-consuming on first page load, but after that, it's not so bad.

Setting up routing for local testing

For login and file upload to work with your local server, you need to edit your /etc/hosts file to include the following: dev-oidc azurite
# Required for test AWS S3 bucket
This provides a local IP route for the 'dev-oidc', 'azurite', and 'localstack' hostnames.

Seeding the development database

Creating questions and programs in CiviForm is a bit time consuming to do manually with the UI, so in dev mode there is a controller action that generates several for you. You can access this feature at localhost:<port number>/dev/seed.

Help! It's not working!

We know setting up a development environment can have some snags in the road. If something isn't working, check out our Troubleshooting guide or reach out on Slack.

Running tests

This section will help you run CiviForm unit and browser tests in a basic way. For more information on writing and debugging these tests, check out the Testing guide.

Running java unit tests

To run the java unit tests (includes all tests under test/), run the following:
If you'd like to run a specific test or set of tests, and/or save sbt startup time each time you run the test(s), use the following steps. This is recommended for developer velocity.
  1. 1.
    Bring up an sbt shell inside the Docker container by running:
  2. 2.
    Run any sbt commands! For example:
    testOnly services.question.types.QuestionDefinitionTest
    testOnly services.question.types.QuestionDefinitionTest -- -z getQuestion*

Running typescript unit tests

To run the unit tests in app/assets/javascripts, run the following:
If you'd like to run a specific test or set of tests, run the following:
bin/run-ts-tests file1.test.ts file2.test.ts

Running browser tests

To run the browser tests (includes all the Playwright tests in civiform/browser-test/src/, there are two steps:
  1. 1.
    Bring up the local test environment using the AWS emulator. Leave this running:
  2. 2.
    Once you see "Server started" in the terminal from the above step, in a separate terminal run the tests in a docker container:
    Or, to run a test in a specific file, you can pass the file path relative to the browser-test/src directory:
    bin/run-browser-tests landing_page.test.ts


Browser tests are heavy handed and can take a while to run. You can focus the run to only execute a single it test or describe suite per file by prefixing it with f. EG: fit and fdescribe.

Creating fake data

To create Questions and Programs that use them, you need to log in as a "Program and CiviForm Admin" through http://localhost:9000/loginForm .
You can return to that screen to switch to a Guest user and back again to an Admin as needed.

Debug logging

You can change the logging levels by editing conf/logback.xml. This can help get a deeper understanding of what the server is doing for development.

Running Coverage

To generate coverage report, run the following:
Navigate to server/code-coverage/report/html/index.html and see the detailed report of the code coverage data and also dig deep to see how much your implemented classes are covered.

Running the formatter

To format your code, run:
By default, this will format any files that have diffs compared to origin/main. Diffing against origin/main, however, can have a lot of noise if you haven't synced in a while. You can run this against a different diffbase with:
bin/fmt -d <diffbase>
For example:
# Diff against your local main branch:
bin/fmt -d main
# Diff against a specific commit:
bin/fmt -d <commit ID>
# Diff against the current commit:
bin/fmt -d HEAD
# Diff against the previous commit:
bin/fmt -d HEAD^

What's next?

To learn more about how to make code contributions, head to Technical contribution guide.
To learn about the CiviForm tech stack and standards, head to Technology overview and Development standards.