Quickstart

Add Skipper to a JVM service and run your first workflow — with zero database setup.

This guide gets Skipper running in an existing JVM service in a few minutes. For a deeper, worked example with tests, see Your First Workflow.

1. Add the dependency

Skipper is published to Maven Central as com.airbnb.skipper:skipper-core. The current version is on the artifact page.

// build.gradle.kts
dependencies {
  implementation("com.airbnb.skipper:skipper-core:0.8.0")
}
<!-- pom.xml -->
<dependency>
  <groupId>com.airbnb.skipper</groupId>
  <artifactId>skipper-core</artifactId>
  <version>0.8.0</version>
</dependency>

If you write workflows in Kotlin, also enable the AllOpen compiler plugin so Skipper can subclass your workflow and action classes (see Kotlin Coroutines).

2. Configure Skipper

Skipper is configured through a SkipperConfig. The only required setting is a unique service name. By default Skipper persists to an embedded, in-memory SQLite store — so there is nothing else to set up to start experimenting: no database to provision and no schema to create.

import com.airbnb.skipper.SkipperConfig

val config = SkipperConfig.forService("my-service")
import com.airbnb.skipper.SkipperConfig;

SkipperConfig config = SkipperConfig.forService("my-service");

The in-memory store is ideal for getting started, local development, and tests — but it is not durable: its state is lost when the process exits. To keep state across restarts on a single node, give the store and the scheduler the same file path instead:

config.workflowStore = SqliteWorkflowStore.Factory("skipper.db")
config.scheduler = SqliteScheduler.Factory("skipper.db")
config.setWorkflowStore(new SqliteWorkflowStore.Factory("skipper.db"));
config.setScheduler(new SqliteScheduler.Factory("skipper.db"));

Both factories are in com.airbnb.skipper.internal.storage.sqlite and com.airbnb.skipper.internal.scheduler.sqlite; the schema is created on first start. For several replicas sharing one store, use MySQL. See Storage Backends.

3. Create the runtime and start the scheduler

SkipperRuntime wires up the engine from your config. Start its scheduler so workflows are driven forward, and keep the runtime around to obtain the workflow factory.

import com.airbnb.skipper.admin.AdminResource
import com.airbnb.skipper.factory.SkipperRuntime

val runtime = SkipperRuntime(config)

// Start the scheduler (stop it on shutdown).
runtime.skipperSchedulerManager.get().start()

// Optional: expose the admin UI by registering this JAX-RS resource with your HTTP layer.
// See Observability & Admin UI for details.
val admin = runtime.adminResource.get()
import com.airbnb.skipper.admin.AdminResource;
import com.airbnb.skipper.factory.SkipperRuntime;

SkipperRuntime runtime = new SkipperRuntime(config);

// Start the scheduler (stop it on shutdown).
runtime.getSkipperSchedulerManager().get().start();

// Optional: expose the admin UI by registering this JAX-RS resource with your HTTP layer.
// See Observability & Admin UI for details.
AdminResource admin = runtime.getAdminResource().get();

4. Write a workflow

A workflow is a class with at least one @WorkflowMethod. An action is a method on an Actions class, annotated with @Execute, where you perform I/O and side effects.

import com.airbnb.skipper.Actions
import com.airbnb.skipper.Execute
import com.airbnb.skipper.Workflow
import com.airbnb.skipper.WorkflowMethod

class GreetingWorkflow : Workflow() {
  private val actions = actions<GreetingActions>()

  @WorkflowMethod
  suspend fun greet(name: String): String = actions.render(name)
}

class GreetingActions : Actions() {
  @Execute
  suspend fun render(name: String): String = "Hello, $name!"
}
import com.airbnb.skipper.Actions;
import com.airbnb.skipper.Execute;
import com.airbnb.skipper.Workflow;
import com.airbnb.skipper.WorkflowMethod;
import java.util.concurrent.CompletableFuture;

public class GreetingWorkflow extends Workflow {
  private final GreetingActions actions = actions(GreetingActions.class);

  @WorkflowMethod(returnType = String.class)
  public CompletableFuture<String> greet(String name) {
    return CompletableFuture.completedFuture(actions.render(name));
  }
}

public class GreetingActions extends Actions {
  @Execute
  public String render(String name) {
    return "Hello, " + name + "!";
  }
}

5. Invoke it

Get the workflow factory from the runtime and start an instance with a unique id.

import com.airbnb.skipper.IWorkflowFactory

val factory: IWorkflowFactory = runtime.workflowFactory.get()

val workflow = factory<GreetingWorkflow>("greeting-42")
val result = workflow.greet("world") // suspends until the workflow completes
import com.airbnb.skipper.IWorkflowFactory;

IWorkflowFactory factory = runtime.getWorkflowFactory().get();

GreetingWorkflow workflow = factory.invoke(GreetingWorkflow.class, "greeting-42");
String result = workflow.greet("world").get(); // blocks until the workflow completes

That’s it — Skipper persists progress as the workflow runs and will drive it to completion even if the process restarts mid-flight.

Next steps