Skip to content

Urban Company Mobile App Development Interview Questions & Answers

Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.

About Urban Company hiring for Mobile App Development roles

Urban Company is an Indian technology platform that connects customers with trained professionals for home services such as cleaning, beauty, appliance repair, plumbing and painting. It handles booking, pricing, partner training and quality control through its app. It hires software engineers, data analysts, product managers and operations roles, and also operates in a few international markets.

For Mobile App Development roles, this Urban Company practice set focuses most on React Native Navigation, State and Native Modules (7), Flutter State Management and Architecture (6), Dart and Flutter Basics (5), Testing, Performance and CI/CD (4). It has 20 medium, 10 hard questions, so you can start easy and work up to the harder ones.

Company type
Product
Headquarters
Gurugram, India
Main India offices
Gurugram

Urban Company Mobile App Development interview process

  1. Online coding or analytics assessment
  2. Technical round 1
  3. Technical round 2 (design or case)
  4. Hiring manager and culture round

Typical pattern based on public candidate experiences. Rounds vary by role, team and year.

Solved for Urban CompanyStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

How do you manage form state and validation across multiple steps in a Flutter onboarding flow?

Save to ▾
Show answer
Keep the onboarding data in one state object owned by a notifier or cubit scoped to the flow, with each step updating its part. Validate per step before moving forward and again on final submit. Save progress locally so users can resume if they leave. Keep validation rules in pure functions that are unit tested. Dispose the state when the flow completes so data does not leak into later sessions.
02

A startup asks you to choose between Flutter, React Native and native for their new delivery app. How do you decide?

Save to ▾
Show answer
I would ask about team skills, timeline, budget, required features and long-term plans. If the team knows JavaScript and has a web app, React Native allows code and skill sharing. If they want a consistent custom UI and fast development from scratch, Flutter is strong. Heavy background location and maps work well in both with plugins, but if the app depends deeply on platform features, native may be safer. I would prototype one key screen first.
03

After a release, crash reports show a spike only on one Android OS version. What steps do you take?

Save to ▾
Show answer
Pause the staged rollout to limit impact. Filter crash reports by OS version and device to find the top stack trace, and check behaviour changes for that version, such as permission, background or edge-to-edge rules. Reproduce on an emulator of that version, fix it, add a regression test and resume rollout with a hotfix. Add that OS version to the regular test device matrix.
04

You are designing a large Flutter app for a bank with 30 developers. How do you structure it?

Save to ▾
Show answer
Split the app into feature packages in a monorepo managed with Melos or pub workspaces, plus core packages for networking, design system, analytics and security. Pick one state management approach, such as Bloc for strict traceability, with clear layer boundaries. Use code generation consistently, enforce lints and architecture tests in CI, and assign feature ownership. Add integration tests for critical journeys and strict security reviews for storage and network code.
05

How do you reduce app size for Flutter and React Native apps?

Save to ▾
Show answer
Publish Android App Bundles so users download only their architecture and density resources. In Flutter, use --split-debug-info and --obfuscate, remove unused packages and fonts, compress images and use tree-shaken icons. In React Native, enable Hermes, R8 minification and resource shrinking, and remove heavy libraries. For both, analyse size with tools like flutter build --analyze-size or APK Analyzer and lazy-load large assets.
06

What is app signing and why must you protect the keys?

Save to ▾
Show answer
Signing proves the app comes from you and that updates are from the same developer. On Android, you sign uploads with an upload key and Play App Signing re-signs with the app signing key held by the store; a lost upload key can be reset, but losing a self-managed app key meant you could never update the app. On iOS, signing uses certificates and provisioning profiles. Store keys in a secure vault and CI secrets, never in the repository.
07

The JS bundle grew large and startup is slow. How do you reduce startup time in React Native?

Save to ▾
Show answer
Measure time to interactive on a release build first. Make sure Hermes is enabled, remove unused dependencies and heavy libraries like full date or icon packs, and lazy-load screens and modules with inline requires. Defer non-critical SDK initialisation until after the first screen. Keep the initial screen light, avoid large synchronous storage reads at startup, and use the New Architecture for faster native module loading.
08

Write a Flutter screen that fetches a list from an API using FutureBuilder.

Save to ▾
Show answer
class UsersPage extends StatefulWidget { const UsersPage({super.key}); @override State<UsersPage> createState() => _UsersPageState(); } class _UsersPageState extends State<UsersPage> { late final Future<List<User>> _future = api.fetchUsers(); @override Widget build(BuildContext context) => FutureBuilder<List<User>>( future: _future, builder: (context, snap) { if (snap.connectionState != ConnectionState.done) { return const Center(child: CircularProgressIndicator()); } if (snap.hasError) return const Center(child: Text('Something went wrong')); final users = snap.data!; return ListView.builder( itemCount: users.length, itemBuilder: (_, i) => ListTile(title: Text(users[i].name)), ); }, ); }
09

How would you migrate a large React Native app from JavaScript to TypeScript?

Save to ▾
Show answer
Enable TypeScript with allowJs so both coexist, start with a relaxed tsconfig, and convert shared code first: API types, models, utilities and navigation param lists. Then convert screens feature by feature, tightening strict options gradually. Add type checks to CI so new files must be TypeScript. Avoid using any to silence errors; use unknown and narrow. Track progress and celebrate milestones to keep momentum.
10

A Flutter animation is smooth on a flagship phone but janky on a budget phone. How do you fix it?

Save to ▾
Show answer
Profile on the budget device in profile mode. Common fixes: wrap frequently repainting areas in RepaintBoundary, avoid expensive effects like Opacity on large subtrees, clipping and shadows in scrolling lists, use AnimatedBuilder with child so static parts do not rebuild, precache images and decode them at display size, and move heavy computation to isolates. Reduce animation complexity on low-end devices if needed.
11

What is a Stream in Dart and how is it used in Flutter?

Save to ▾
Show answer
A Stream delivers a sequence of asynchronous events, such as real-time database updates, location changes or WebSocket messages. You listen with listen() or await for, and transform with map, where and debounce from packages. Single-subscription streams allow one listener; broadcast streams allow many. In Flutter, StreamBuilder rebuilds UI on each event. Always cancel subscriptions in dispose to prevent leaks.
12

What is BuildContext?

Save to ▾
Show answer
BuildContext is a handle to a widget's location in the element tree. It is used to look up inherited data like Theme.of(context), MediaQuery and Navigator, and providers. Each widget's build method gets its own context. Common mistakes are using a context from above a widget that provides data, or using a context after an async gap when the widget may be unmounted; check context.mounted before using it after await.
13

What are isolates and when should you use them?

Save to ▾
Show answer
Isolates are Dart's units of concurrency, each with its own memory and event loop, communicating by messages. Heavy CPU work like parsing a large JSON file, image processing or encryption on the main isolate causes jank. Use Isolate.run or compute to run such work in a separate isolate and return the result. For network or file I/O, async-await is enough because that work is not CPU-bound.
14

How would you test a Bloc or Riverpod notifier?

Save to ▾
Show answer
Test business logic without widgets. For Bloc, the bloc_test package's blocTest builds the bloc with a fake repository, acts by adding events, and expects a list of emitted states. For Riverpod, create a ProviderContainer with overrides for repository providers, read the notifier, call methods and assert the state. Use mocktail for mocks and keep tests fast, deterministic and independent of the network.
15

The app takes six seconds to start on low-end phones. How do you improve it?

Save to ▾
Show answer
Measure cold start on a release or profile build and trace what runs before the first frame. Defer non-critical SDK initialisation such as analytics and ads, avoid large synchronous storage reads and network calls before showing UI, load the first screen with cached data, and lazy-load other features. In Flutter, keep main() light; in React Native, use Hermes and inline requires. Use a native splash screen to avoid a blank screen.
16

Write a Dart HTTP client using dio with an interceptor that adds an auth token.

Save to ▾
Show answer
final dio = Dio(BaseOptions( baseUrl: 'https://api.example.com', connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 15), )); dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) async { final token = await secureStorage.read(key: 'access_token'); if (token != null) options.headers['Authorization'] = 'Bearer $token'; handler.next(options); }, onError: (e, handler) { if (e.response?.statusCode == 401) authNotifier.logout(); handler.next(e); }, ));
17

A global Redux store causes the whole app to re-render on every small change. How do you fix it?

Save to ▾
Show answer
Components are probably selecting large parts of state or creating new objects in selectors. Select only the fields each component needs with useSelector, memoise derived data with createSelector, and keep state normalised. Move server data to RTK Query or TanStack Query and local UI state back into components. Verify improvements with the React profiler, checking which components render after each action.
18

Write an EAS configuration for development, preview and production builds.

Save to ▾
Show answer
{ "cli": { "version": ">= 12.0.0" }, "build": { "development": { "developmentClient": true, "distribution": "internal" }, "preview": { "distribution": "internal", "channel": "preview" }, "production": { "autoIncrement": true, "channel": "production" } }, "submit": { "production": {} } }
19

Users get logged out randomly. The access token refresh seems to fail sometimes. What could be wrong?

Save to ▾
Show answer
A common cause is a race condition: several requests receive 401 at once and each triggers a refresh, so later refreshes use an already rotated refresh token and fail, logging the user out. Fix it by allowing only one refresh at a time and queueing other requests until it completes, then retrying them with the new token. Also check device clock issues, token expiry settings and secure storage read failures.
20

Write a go_router configuration with an auth redirect.

Save to ▾
Show answer
final router = GoRouter( initialLocation: '/', refreshListenable: authNotifier, redirect: (context, state) { final loggedIn = authNotifier.isLoggedIn; final goingToLogin = state.matchedLocation == '/login'; if (!loggedIn && !goingToLogin) return '/login'; if (loggedIn && goingToLogin) return '/'; return null; }, routes: [ GoRoute(path: '/', builder: (_, __) => const HomePage()), GoRoute(path: '/login', builder: (_, __) => const LoginPage()), GoRoute( path: '/product/:id', builder: (_, state) => ProductPage(id: state.pathParameters['id']!), ), ], );
21

Write a Dart sealed class for API results and handle it with an exhaustive switch.

Save to ▾
Show answer
sealed class Result<T> {} class Success<T> extends Result<T> { Success(this.data); final T data; } class Failure<T> extends Result<T> { Failure(this.message); final String message; } Widget view(Result<List<String>> r) => switch (r) { Success(:final data) => ListView(children: [for (final s in data) Text(s)]), Failure(:final message) => Center(child: Text(message)), };
22

Push notifications arrive on Android but not on iOS. How do you debug it?

Save to ▾
Show answer
Check that the push notifications capability and background modes are enabled in Xcode, that an APNs authentication key is uploaded to the push provider, and that notification permission was granted. Verify the app gets an APNs token and the provider token, and that the right environment, development or production, is used. Test on a real device, since simulators have limited push support, and check payload format.
23

How do animations work in React Native and why use Reanimated?

Save to ▾
Show answer
The built-in Animated API can run animations on the native thread with useNativeDriver for transform and opacity, but not for layout properties. Reanimated runs animation logic in worklets on the UI thread, so animations stay smooth even if JavaScript is busy, and supports gestures, layout animations and shared element transitions. Combined with react-native-gesture-handler, it is the standard for complex interactive animations.
24

Users lose their place in a long Flutter form when they get a phone call and the app is killed in background. How do you fix it?

Save to ▾
Show answer
The operating system may kill the app process in background, and in-memory state is lost. Save draft form data to local storage, such as shared_preferences, Hive or a SQLite table, as the user types with a short debounce, and restore it when the screen opens. Flutter's RestorationMixin and restorationScopeId can restore simple UI state like scroll position and text fields. Clear the draft after successful submission.
25

How do you force users to update when an old version has a critical bug?

Save to ▾
Show answer
Keep a minimum supported version in remote config or an API endpoint, check it at startup and show a blocking update screen linking to the store. On Android, use the Play In-App Updates API with the immediate flow for critical updates and flexible flow for normal ones. Keep the backend compatible with older versions for a defined period, and use forced updates sparingly because they frustrate users.
26

How do you write a Fabric native component or use one in React Native?

Save to ▾
Show answer
A Fabric component wraps a native view for use in JavaScript. You write a TypeScript spec using codegenNativeComponent with typed props, run Codegen to generate C++ and platform interfaces, and implement the view in Kotlin and Objective-C or Swift. With Expo, the Expo Modules API lets you define a native view in Kotlin and Swift with less boilerplate. Use this for maps, video players or custom SDK views.
27

An over-the-air update crashed the app for users on an older native build. What went wrong and how do you prevent it?

Save to ▾
Show answer
The update probably used a native module or API that the older binary did not have, so JavaScript called missing native code. Prevent this by setting runtime versions tied to native code fingerprints, so updates only reach compatible builds. Roll out updates gradually, monitor crashes per update ID, and keep a rollback by republishing the previous update. Test updates on the oldest supported build before release.
28

The cart total shows stale values on the checkout screen after items are removed on the cart screen. How do you fix it?

Save to ▾
Show answer
Each screen probably holds its own copy of cart data. Move cart state into a single shared state object, such as a Riverpod notifier or a Cubit provided above both screens, and have both screens watch it. All mutations go through that object, which emits a new immutable state. Derived values like total should be computed from the state, not stored separately, so they can never become inconsistent.
29

An animation stutters whenever the screen fetches data. How do you fix it?

Save to ▾
Show answer
The animation likely runs on the JS thread, and data parsing or re-renders block it. Move the animation to the UI thread with Reanimated or Animated with useNativeDriver, reduce the work done when data arrives by memoising components and normalising state updates, and delay heavy processing with InteractionManager or requestIdleCallback-style scheduling until the animation finishes. Profile with React Native DevTools to confirm.
30

How do you handle gestures such as swipe to delete in React Native?

Save to ▾
Show answer
Use react-native-gesture-handler, which processes gestures on the native side, often with Reanimated for smooth animations. For swipe to delete, the Swipeable or ReanimatedSwipeable component renders action buttons behind a row. Define gestures with the Gesture API, such as Gesture.Pan, and compose them when needed. Wrap the app root in GestureHandlerRootView. Provide an accessible alternative like a long-press menu for screen reader users.

Tips to crack the Urban Company Mobile App Development interview

  • Practise DSA and low-level design for engineering roles, such as designing a booking or slot allocation system.
  • For analyst roles, prepare marketplace metrics like fill rate, repeat rate and partner earnings, and practise related SQL queries.
  • Understand the two-sided marketplace model of customers and service partners, and discuss how both sides stay satisfied.
  • Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
  • Practise the hard questions on this page aloud; Urban Company interviewers usually ask follow-ups on your first answer.

Frequently asked questions

How many rounds are there in the Urban Company Mobile App Development interview?

Candidates usually go through 4 stages: Online coding or analytics assessment; Technical round 1; Technical round 2 (design or case); Hiring manager and culture round. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.

Which topics should I prepare for the Urban Company Mobile App Development interview?

This practice set leans on React Native Navigation, State and Native Modules (7), Flutter State Management and Architecture (6), Dart and Flutter Basics (5), Testing, Performance and CI/CD (4). Revise those first, then practise explaining one or two of your own projects end to end, because most Urban Company interviewers ask you to walk through real work.

Are these the exact questions asked at Urban Company?

No. These are curated practice questions that match the skills and difficulty usually tested in product interviews like Urban Company's. They are not a leaked or verified list of past questions.

Where does Urban Company hire Mobile App Development professionals in India?

Urban Company has large teams in Gurugram. Openings and locations change often, so check the Urban Company careers page and filter by city and experience.

Mobile App Development questions for similar companies