Skip to main content
Kraken provides flexibility to create custom workflows for projects that don’t follow the standard Django + React structure. You can compose workflows from individual components to match your specific needs.

When to Use Custom Workflows

Use custom workflows when your repository:
  • Has multiple frontend or backend projects
  • Requires a non-standard build pipeline
  • Needs specific job dependencies or ordering
  • Uses different technology stacks in the same repository

Basic Workflow Structure

Instead of using LabsApplicationStack, create a custom workflow using the Workflow, project classes, and job components:
import { Workflow } from 'cdkactions';
import { DjangoProject, ReactProject, DeployJob } from '@pennlabs/kraken';

const workflow = new Workflow(this, 'workflow', {
  name: 'Workflow',
  on: 'push',
});

Composing Projects

Single Django, Multiple Frontends

From the README “Different Configuration” section (README.md:36-70), here’s how to configure a repository with one Django backend and multiple React frontends:
const workflow = new Workflow(this, 'workflow', {
  name: 'Workflow',
  on: 'push',
});

const django = new DjangoProject(workflow,
  {
    projectName: 'djangoProject',
    path: 'backend',
    imageName: 'project-backend',
  });

const reactOne = new ReactProject(workflow,
  {
    id: 'one',
    path: 'frontendOne',
    imageName: 'project-frontendOne',
  });

const reactTwo = new ReactProject(workflow,
  {
    id: 'two',
    path: 'frontendTwo',
    imageName: 'project-frontendTwo',
  });

new DeployJob(workflow, {},
  {
    needs: [django.publishJobId, reactOne.publishJobId, reactTwo.publishJobId],
  });
This configuration will:
  1. Lint and test the Django project
  2. Lint and test both React projects
  3. Build and publish Docker images for all three projects
  4. Deploy the application once all images are published

Working with Project Classes

DjangoProject

The DjangoProject class creates a check job and a publish job that run sequentially (django-project.ts:58):
const django = new DjangoProject(workflow, {
  id: 'api',              // Optional: custom ID suffix
  projectName: 'myapi',   // Django project name
  path: 'backend',        // Path to Django code
  imageName: 'my-api',    // Docker image name
  
  // Optional: customize check job
  checkProps: {
    pythonVersion: '3.11',
  },
  
  // Optional: customize publish job
  publishProps: {
    dockerfile: 'Dockerfile.prod',
  },
});

// Access the publish job ID for dependencies
const publishJobId = django.publishJobId;

ReactProject

The ReactProject class works similarly (react-project.ts:53):
const frontend = new ReactProject(workflow, {
  id: 'admin',              // Optional: custom ID suffix
  path: 'frontend/admin',   // Path to React code
  imageName: 'my-admin',    // Docker image name
  
  // Optional: customize check job
  checkProps: {
    nodeVersion: '18',
  },
  
  // Optional: customize publish job
  publishProps: {
    cache: true,
  },
});

Advanced Job Dependencies

Parallel and Sequential Jobs

Control job execution order using the needs parameter:
// Projects run in parallel (no dependencies)
const django = new DjangoProject(workflow, { /* ... */ });
const react1 = new ReactProject(workflow, { /* ... */ });
const react2 = new ReactProject(workflow, { /* ... */ });

// Deploy waits for all projects
new DeployJob(workflow, {}, {
  needs: [
    django.publishJobId,
    react1.publishJobId,
    react2.publishJobId,
  ],
});

Custom Job Overrides

Override default job properties:
const django = new DjangoProject(workflow, {
  projectName: 'myproject',
  path: 'backend',
  imageName: 'backend',
}, {
  // Job overrides
  checkOverrides: {
    runsOn: 'ubuntu-22.04',
    timeoutMinutes: 30,
  },
  publishOverrides: {
    if: "github.ref == 'refs/heads/production'",
  },
});

Image Naming

Images follow the pennlabs/{imageName} convention (docker.ts:111):
// Results in: pennlabs/project-backend:latest
const django = new DjangoProject(workflow, {
  imageName: 'project-backend',
  // ...
});

// Results in: pennlabs/project-admin-frontend:latest
const react = new ReactProject(workflow, {
  imageName: 'project-admin-frontend',
  // ...
});

Complete Example: Multi-Service Application

import { Workflow } from 'cdkactions';
import { DjangoProject, ReactProject, DeployJob } from '@pennlabs/kraken';

const workflow = new Workflow(this, 'workflow', {
  name: 'Build and Deploy',
  on: 'push',
});

// API backend
const api = new DjangoProject(workflow, {
  id: 'api',
  projectName: 'api',
  path: 'services/api',
  imageName: 'myapp-api',
});

// Admin dashboard
const admin = new ReactProject(workflow, {
  id: 'admin',
  path: 'frontends/admin',
  imageName: 'myapp-admin',
});

// Public website
const website = new ReactProject(workflow, {
  id: 'website',
  path: 'frontends/website',
  imageName: 'myapp-website',
});

// Mobile API backend
const mobileApi = new DjangoProject(workflow, {
  id: 'mobile-api',
  projectName: 'mobile_api',
  path: 'services/mobile-api',
  imageName: 'myapp-mobile-api',
});

// Deploy after all services are built
new DeployJob(workflow, {}, {
  needs: [
    api.publishJobId,
    admin.publishJobId,
    website.publishJobId,
    mobileApi.publishJobId,
  ],
});
This workflow:
  • Builds 4 services in parallel
  • Publishes 4 Docker images
  • Deploys only after all images are ready
  • Runs on every push to the repository

Build docs developers (and LLMs) love