Skillz Backend Engineer Role:

If you’re reading this, there’s a good chance you spend your days thinking about databases, APIs, and how to make things run faster. (No judgment—we do too.) And if you’ve ever secretly smiled when a tricky piece of code finally worked? Yeah, you’re in the right place.
What is Skillz Inc.? Company Overview

- What we do: We make mobile gaming competitive.
- How we do it: By giving developers tools to add tournaments, prizes, and real-money play to their games.
- Why it matters: Because competition is fun, and we believe anyone with skill should have a shot at winning.
Backend Engineer Job Overview – Skillz Bengaluru

Backend Engineer Eligibility & Skills Required
Eligibility Criteria
| Criteria | Requirement |
|---|---|
| Experience | 6 months – 2 years |
| Education | Bachelor’s in Computer Science or equivalent |
| Work Mode | In-office 3 days a week (Bengaluru) |
| Industry | Gaming experience preferred, not mandatory |
Skills Required
| Skill Area | What You Need |
|---|---|
| Languages | Golang (Go) OR Java |
| Core CS | Data structures, algorithms, OOP, complexity analysis |
| Distributed Systems | Multi-tiered systems, caching (Redis/Memcached), relational databases |
| Cloud | AWS, Azure, or GCP |
| Microservices | Building new services or enhancing existing ones |
| System Design | Low-level design (LLD) from requirements |
| Operations | System KPIs, SLAs, reliability improvements |
| Communication | Clear technical articulation across teams |
Backend Engineer Roles and Responsibilities at Skillz
What You’ll Do Day-to-Day
| 🚀 | Build & Scale — Create backend systems that power millions of tournaments |
| 💻 | Write Code — Ship clean, scalable code in Go or Java |
| 📐 | Design Systems — Turn ideas into precise low-level designs (LLD) |
| 🔧 | Build Microservices — Create new services and improve existing ones |
| 🗄️ | Handle Data — Work with Redis, Memcached, and relational databases |
| ☁️ | Deploy on Cloud — Use AWS, Azure, or GCP like a pro |
| 📊 | Keep Things Fast — Improve system KPIs, SLAs, and reliability |
| 🤝 | Collaborate — Work with product, frontend, and QA teams |
| 🎙️ | Share Ideas — Explain technical stuff clearly to anyone |
Skillz Backend Engineer Hiring Process
Simple. Transparent. Human.
Application Review — We review your resume. If it’s a match, we reach out within 5–7 days.
Recruiter Screening — A 30-min friendly chat. We get to know you. You get to know us.
Technical Assessment — A practical coding exercise in Go or Java. No tricks. Just real problem-solving.
Technical Interviews — 2–3 rounds covering system design, distributed systems, and how you think.
Leadership & Culture Fit — A conversation about your growth, values, and what makes you tick.
Offer & Onboarding — Welcome to the team! We’ll help you settle in and start making impact from day one.
Skillz Backend Engineer Salary & Benefits
Compensation
| Component | Details |
|---|---|
| Base Salary | Competitive, based on experience |
| Bonus | Annual performance bonus |
| Equity | Stock options – share in Skillz success |
Perks
| Benefit | Details |
|---|---|
| Health Insurance | Coverage for you and dependents |
| Tax Savings | FBP for fuel, internet, phone bills |
| Retirement | National Pension System (NPS) |
| Work Mode | Hybrid – 3 days in-office |
| Growth | Mentorship from top tech experts |
5 Mistakes to Avoid – Backend Engineer Role at Skillz
🚫 Listing languages you barely know — Show real Go or Java experience.
⚡ Ignoring scale stories — Mention Redis, Memcached, or performance wins.
💤 Applying like any other job — Tell us why Skillz excites you.
🌀 Skipping system thinking — Practice low-level design basics.
🔧 Only hyping new features — Share how you kept systems reliable.
⚡ Skillz Backend Engineer | Coding Interview Questions
Golang • Java • Distributed Systems • Concurrency • System Design • Real-World Problems
📖 Problem
Design a rate limiter that allows at most N requests per second per user. Implement the allowRequest(userId) method. This tests your understanding of caching, concurrency, and distributed systems.
📤 Output: First 3 requests return true, 4th request within same second returns false
☕ Java Code — Token Bucket
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class RateLimiter {
private final int maxRequests;
private final long windowMs;
private final ConcurrentHashMap<String, AtomicLong> counterMap = new ConcurrentHashMap<>();
public RateLimiter(int maxRequests, long windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
}
public boolean allowRequest(String userId) {
long now = System.currentTimeMillis();
long windowKey = now / windowMs;
String key = userId + ":" + windowKey;
AtomicLong counter = counterMap.computeIfAbsent(key, k -> new AtomicLong(0));
// Clean up old entries
if (counterMap.size() > 1000) {
counterMap.entrySet().removeIf(entry ->
Long.parseLong(entry.getKey().split(":")[1]) < (now / windowMs) - 2);
}
return counter.incrementAndGet() <= maxRequests;
}
public static void main(String[] args) throws InterruptedException {
RateLimiter limiter = new RateLimiter(3, 1000);
System.out.println(limiter.allowRequest("user1")); // true
System.out.println(limiter.allowRequest("user1")); // true
System.out.println(limiter.allowRequest("user1")); // true
System.out.println(limiter.allowRequest("user1")); // false
Thread.sleep(1000);
System.out.println(limiter.allowRequest("user1")); // true (new window)
}
}
📖 Problem
Implement an in-memory cache that supports put(key, value, ttl) and get(key) with automatic expiry. Must be thread-safe — exactly what you'd use with Redis/Memcached.
☕ Java Code — Concurrent Cache
import java.util.concurrent.*;
import java.util.*;
public class TTLCache<K, V> {
private static class CacheEntry<V> {
V value;
long expiryTime;
CacheEntry(V value, long ttlMs) {
this.value = value;
this.expiryTime = System.currentTimeMillis() + ttlMs;
}
boolean isExpired() {
return System.currentTimeMillis() > expiryTime;
}
}
private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor();
public TTLCache() {
cleaner.scheduleAtFixedRate(this::cleanExpired, 1, 1, TimeUnit.SECONDS);
}
public void put(K key, V value, long ttlMs) {
cache.put(key, new CacheEntry<>(value, ttlMs));
}
public V get(K key) {
CacheEntry<V> entry = cache.get(key);
if (entry == null || entry.isExpired()) {
cache.remove(key);
return null;
}
return entry.value;
}
private void cleanExpired() {
cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
}
public static void main(String[] args) throws InterruptedException {
TTLCache<String, String> cache = new TTLCache<>();
cache.put("tournament", "active", 2000);
System.out.println(cache.get("tournament")); // active
Thread.sleep(2500);
System.out.println(cache.get("tournament")); // null
}
}
📖 Problem
Process 1000 tournament match results using a worker pool of 10 goroutines. This tests your understanding of Go concurrency, channels, and wait groups — essential for high-throughput backend services.
🐹 Golang Code — Worker Pool
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
// Simulate processing tournament result
time.Sleep(10 * time.Millisecond)
results <- job * 2 // some processing
fmt.Printf("Worker %d processed job %d\n", id, job)
}
}
func main() {
const numJobs = 1000
const numWorkers = 10
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
// Start workers
for w := 1; w <= numWorkers; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// Send jobs
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// Wait for all workers to finish
go func() {
wg.Wait()
close(results)
}()
// Collect results
count := 0
for result := range results {
count++
_ = result
}
fmt.Printf("Processed %d results\n", count)
}
📖 Problem
Design an ATM machine with withdraw, deposit, and balance check functionality. Focus on object-oriented design, encapsulation, and state management — exactly what you'll do when building microservices at Skillz.
☕ Java Code — ATM LLD
import java.util.*;
interface ATMState {
void insertCard();
void ejectCard();
void enterPin(int pin);
void requestCash(int amount);
}
class ATM {
private ATMState state;
private int balance;
private boolean cardInserted;
private int enteredPin;
public ATM(int initialBalance) {
this.balance = initialBalance;
this.state = new IdleState(this);
this.cardInserted = false;
}
void setState(ATMState state) { this.state = state; }
int getBalance() { return balance; }
void setBalance(int balance) { this.balance = balance; }
boolean isCardInserted() { return cardInserted; }
void setCardInserted(boolean inserted) { this.cardInserted = inserted; }
void setEnteredPin(int pin) { this.enteredPin = pin; }
int getEnteredPin() { return enteredPin; }
public void insertCard() { state.insertCard(); }
public void ejectCard() { state.ejectCard(); }
public void enterPin(int pin) { state.enterPin(pin); }
public void requestCash(int amount) { state.requestCash(amount); }
}
class IdleState implements ATMState {
private ATM atm;
IdleState(ATM atm) { this.atm = atm; }
public void insertCard() {
System.out.println("Card inserted");
atm.setCardInserted(true);
atm.setState(new HasCardState(atm));
}
public void ejectCard() { System.out.println("No card to eject"); }
public void enterPin(int pin) { System.out.println("Insert card first"); }
public void requestCash(int amount) { System.out.println("Insert card first"); }
}
class HasCardState implements ATMState {
private ATM atm;
HasCardState(ATM atm) { this.atm = atm; }
public void insertCard() { System.out.println("Card already inserted"); }
public void ejectCard() {
System.out.println("Card ejected");
atm.setCardInserted(false);
atm.setState(new IdleState(atm));
}
public void enterPin(int pin) {
if (pin == 1234) {
System.out.println("PIN correct");
atm.setState(new AuthenticatedState(atm));
} else {
System.out.println("Wrong PIN");
ejectCard();
}
}
public void requestCash(int amount) { System.out.println("Enter PIN first"); }
}
class AuthenticatedState implements ATMState {
private ATM atm;
AuthenticatedState(ATM atm) { this.atm = atm; }
public void insertCard() { System.out.println("Card already inserted"); }
public void ejectCard() {
System.out.println("Card ejected");
atm.setCardInserted(false);
atm.setState(new IdleState(atm));
}
public void enterPin(int pin) { System.out.println("PIN already entered"); }
public void requestCash(int amount) {
if (amount <= atm.getBalance()) {
atm.setBalance(atm.getBalance() - amount);
System.out.println("Withdrawn: " + amount + ", Remaining: " + atm.getBalance());
ejectCard();
} else {
System.out.println("Insufficient balance");
ejectCard();
}
}
}
public class ATMMachine {
public static void main(String[] args) {
ATM atm = new ATM(2000);
atm.insertCard();
atm.enterPin(1234);
atm.requestCash(500);
}
}
📖 Problem
Design a distributed counter that safely increments across multiple threads/nodes. At Skillz, you'll handle millions of concurrent tournament score updates — this tests your understanding of atomic operations and consistency.
☕ Java Code — Atomic Counter
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.*;
import java.util.*;
public class DistributedCounter {
private final AtomicLong counter = new AtomicLong(0);
public long increment() {
return counter.incrementAndGet();
}
public long get() {
return counter.get();
}
public static void main(String[] args) throws InterruptedException {
DistributedCounter counter = new DistributedCounter();
int numThreads = 100;
int incrementsPerThread = 1000;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
CountDownLatch latch = new CountDownLatch(numThreads);
for (int i = 0; i < numThreads; i++) {
executor.submit(() -> {
for (int j = 0; j < incrementsPerThread; j++) {
counter.increment();
}
latch.countDown();
});
}
latch.await();
executor.shutdown();
System.out.println("Final counter: " + counter.get());
System.out.println("Expected: " + (numThreads * incrementsPerThread));
}
}
Backend Engineer Role Skillz - FAQs
- Need gaming experience?
No. Backend skills matter more. - Remote or in-office?
Hybrid – 3 days a week in Bengaluru. - Know Java but not Go?
Yes, apply. Openness to learn Go is key. - What's in the technical interview?
LLD, system design, data structures, and coding in Go/Java. - Response time?
5–7 business days after applying.
How To Apply for Skillz Backend Engineer
Ready to Level Up Your Career?
Join Skillz Bengaluru and build the future of mobile eSports
📍 Location: Skillz, Table Space Towers, Krishnarajapuram, Bengaluru
Final Pro Tip
Don't just tell us what you've done — show us how you think. When you write your application or walk into the interview, share the *why* behind your decisions. That's what sets great engineers apart.
