6 days ago
i'm not able to run ./gradlew flywayMigrate tastk during pre-deploy how can i do it? here my dockerfile and my build.gradle
# Stage 1: Build Kotlin app with Gradle
FROM gradle:8-jdk21 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle buildFatJar --no-daemon
# Stage 2: Generate openapi.json with Redocly CLI
FROM node:18-alpine AS redocly-builder
WORKDIR /app
COPY --from=build /home/gradle/src/openapi-gen ./openapi-gen
RUN npm install -g @redocly/cli
RUN redocly bundle openapi-gen/documentation.yaml --output openapi.json
# Stage 3: Final runtime image
FROM eclipse-temurin:21-jdk-jammy
EXPOSE 8080
RUN mkdir /app
WORKDIR /app
# Copy Kotlin fat JAR
COPY --from=build /home/gradle/src/build/libs/displate-companies.jar /app/displate-companies.jar
# Copy generated openapi.json
COPY --from=redocly-builder /app/openapi.json /app/openapi.json
CMD ["/bin/sh", "-c", "java -jar /app/displate-companies.jar"]
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import io.gitlab.arturbosch.detekt.Detekt
import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask
plugins {
application
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.sqldelight)
alias(libs.plugins.flyway)
alias(libs.plugins.detekt)
alias(libs.plugins.ktor)
id("com.github.johnrengelman.shadow") version "8.1.1"
}
group = "capibara.org"
version = "0.0.1"
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(21))
vendor.set(JvmVendorSpec.ADOPTIUM)
}
}
buildscript {
dependencies {
classpath(libs.postgresql)
classpath(libs.flyway.postgresql)
}
}
application {
mainClass.set("io.ktor.server.netty.EngineMain")
applicationDefaultJvmArgs = listOf(
"-Dio.ktor.development=${project.findProperty("development") ?: "false"}",
"-XX:+UseContainerSupport"
)
sqldelight {
databases {
create("DisplateDatabase") {
packageName.set("org.capibara")
dialect("app.cash.sqldelight:postgresql-dialect:2.0.2")
deriveSchemaFromMigrations.set(true)
migrationOutputDirectory = file("src/main/kotlin/db/migrations")
migrationOutputFileFormat = ".sql"
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
dependsOn("generateMainDisplateDatabaseMigrations")
}
tasks.getByName("detekt").mustRunAfter("generateMainDisplateDatabaseMigrations")
tasks.withType<Detekt>().configureEach {
reports {
html.required.set(true)
xml.required.set(true)
txt.required.set(true)
sarif.required.set(true)
md.required.set(true)
}
}
tasks.withType<Detekt>().configureEach {
jvmTarget = "1.8"
}
tasks.withType<DetektCreateBaselineTask>().configureEach {
jvmTarget = "1.8"
}
tasks.withType<ShadowJar> {
manifest {
attributes(
"Main-Class" to application.mainClass.get(),
"Implementation-Version" to project.version
)
}
archiveFileName.set("displate-companies.jar")
}
tasks.register("stage") {
dependsOn("shadowJar")
}
flyway {
user = System.getenv("POSTGRES_USER")
password = System.getenv("POSTGRES_PASSWORD")
url = System.getenv("DATABASE_URL")
locations = arrayOf("filesystem:src/main/kotlin/db/migrations")
baselineOnMigrate = true
baselineVersion = "1"
sqlMigrationPrefix = "v"
}
}
3 Replies
6 days ago
You won’t be able to run flywayMigrate
during the Docker image build stage on Railway because the build phase doesn't have access to your Railway Postgres instance—it's only available at runtime, once the container is running.
The recommended approach is to run the flywayMigrate
task as part of your container’s startup command. Here's how you can adjust your Dockerfile:
# ... keep your build and redocly stages as is
# Runtime stage
FROM eclipse-temurin:21-jdk-jammy
WORKDIR /app
# Copy fat jar
COPY --from=build /home/gradle/src/build/libs/displate-companies.jar .
# Copy gradle wrapper and migration scripts
COPY --from=build /home/gradle/src/gradlew .
COPY --from=build /home/gradle/src/gradle ./gradle
COPY --from=build /home/gradle/src/src/main/kotlin/db/migrations ./src/main/kotlin/db/migrations
RUN chmod +x ./gradlew
CMD /bin/sh -c "./gradlew -p /app flywayMigrate --no-daemon && java -jar displate-companies.jar"
This setup runs the migration at startup when the container has access to your Railway-provided environment variables and database. Flyway is idempotent, so this is safe to run on every deploy—it'll just skip if there are no new migrations.
Let me know if you need help adapting this further!
3 days ago
What does your pre deploy look like?
2 days ago
Since Railway doesn't support a separate pre-deploy step for Docker services with access to the internal Postgres instance, I handle database migrations during container startup instead.
In my Dockerfile
, I include the flywayMigrate
Gradle task in the container’s CMD
, like this:
CMD /bin/sh -c "./gradlew -p /app flywayMigrate --no-daemon && java -jar displate-companies.jar"
This ensures the migration runs just before the app starts, and it works because the environment variables for the database (like DATABASE_URL
, POSTGRES_USER
, POSTGRES_PASSWORD
) are only available at runtime—not during the image build.
Flyway is safe to run like this since it will skip already-applied migrations, so even if the container restarts, it won’t reapply anything.