diff --git a/opentech/apply/funds/migrations/0029_applicationsubmission_next.py b/opentech/apply/funds/migrations/0029_applicationsubmission_next.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f3baa78691bf7c70d430d729d9d0b9895235413
--- /dev/null
+++ b/opentech/apply/funds/migrations/0029_applicationsubmission_next.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.0.2 on 2018-03-14 11:15
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funds', '0028_update_on_delete_django2'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='applicationsubmission',
+            name='next',
+            field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='previous', to='funds.ApplicationSubmission'),
+        ),
+    ]
diff --git a/opentech/apply/funds/models.py b/opentech/apply/funds/models.py
index bb6ad0786ad40332c9c2ed006da66d935b471269..b40577b761f7f7c454b978eca889bf1f1eddb758 100644
--- a/opentech/apply/funds/models.py
+++ b/opentech/apply/funds/models.py
@@ -479,6 +479,7 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission):
         related_name='submission_lead',
         on_delete=models.PROTECT,
     )
+    next = models.OneToOneField('self', on_delete=models.CASCADE, related_name='previous', null=True)
     user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
     search_data = models.TextField()
 
@@ -536,7 +537,12 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission):
     def handle_file(self, file):
         # File is potentially optional
         if file:
-            filename = self.save_path(file.name)
+            try:
+                filename = self.save_path(file.name)
+            except AttributeError:
+                # file is not changed, it is still the dictionary
+                return file
+
             saved_name = default_storage.save(filename, file)
             return {
                 'name': file.name,
@@ -565,6 +571,7 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission):
                 file = self.form_data[field.id]
                 self.form_data[field.id] = self.handle_files(file)
 
+        progressing_stage = False
         if not self.id:
             # We are creating the object default to first stage
             try:
@@ -579,11 +586,20 @@ class ApplicationSubmission(WorkflowHelpers, AbstractFormSubmission):
             except AttributeError:
                 # Its a lab
                 self.lead = self.page.specific.lead
+        else:
+            submission_in_db = ApplicationSubmission.objects.get(id=self.id)
+            if self.stage != submission_in_db.stage:
+                progressing_stage = True
+                self.id = None
 
         # add a denormed version of the answer for searching
         self.search_data = ' '.join(self.prepare_search_values())
 
-        return super().save(*args, **kwargs)
+        super().save(*args, **kwargs)
+
+        if progressing_stage:
+            submission_in_db.next = self
+            submission_in_db.save()
 
     def data_and_fields(self):
         for stream_value in self.form_fields:
diff --git a/opentech/apply/funds/tests/test_models.py b/opentech/apply/funds/tests/test_models.py
index caff470b997bf74ed0a59f7cb5fd11ff2ff3c51d..c18280c098e6c4f3a59e02db9f89f9b0ab499135 100644
--- a/opentech/apply/funds/tests/test_models.py
+++ b/opentech/apply/funds/tests/test_models.py
@@ -374,3 +374,20 @@ class TestApplicationSubmission(TestCase):
         submission = self.make_submission(form_data__image__filename=filename)
         save_path = os.path.join(settings.MEDIA_ROOT, submission.save_path(filename))
         self.assertTrue(os.path.isfile(save_path))
+
+
+class TestApplicationProgression(TestCase):
+    def test_new_submission_created(self):
+        submission = ApplicationSubmissionFactory(round__workflow_name='double')
+        self.assertEqual(ApplicationSubmission.objects.count(), 1)
+        old_id = submission.id
+
+        # Update the status to the first phase of the new stage
+        submission.status = str(submission.workflow.stages[1].first())
+        submission.save()
+
+        old_submission = ApplicationSubmission.objects.get(id=old_id)
+
+        self.assertEqual(ApplicationSubmission.objects.count(), 2)
+        self.assertEqual(submission.previous, old_submission)
+        self.assertEqual(old_submission.next, submission)
diff --git a/opentech/apply/funds/workflow.py b/opentech/apply/funds/workflow.py
index 02fd0f82191ef82d0d71047b83e0633c53d2a057..592516cd66c02b6e927c23b2dc3a42cea469efb5 100644
--- a/opentech/apply/funds/workflow.py
+++ b/opentech/apply/funds/workflow.py
@@ -128,6 +128,12 @@ class Stage(Iterable):
         # Make the phases new instances to prevent errors with mutability
         self.phases = self.copy_phases(self.phases)
 
+    def __eq__(self, other):
+        if isinstance(other, Stage):
+            return self.name == other.name
+
+        return super().__eq__(other)
+
     def copy_phases(self, phases: List['Phase']) -> List['Phase']:
         new_phases = list()
         for step, phase in enumerate(self.phases):