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.

Package coordinates and module names below are illustrative and will be finalized with the first public release.

1. Add the dependency

Add Skipper to your build.

// build.gradle.kts
dependencies {
  implementation("dev.skipper:skipper:0.1.0")
}

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.

val config = SkipperConfig.forService("my-service")
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. For production, point Skipper at a persistent backend such as 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.

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()
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.

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!"
}
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.

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

val workflow = factory<GreetingWorkflow>("greeting-42")
val result = workflow.greet("world") // suspends until the workflow completes
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